同步模式
JavaScript 中,在执行同步代码时,会按照代码书写的顺序,从上到下逐行执行,每一个任务都必须等待前一个任务执行完毕,才能拿到结果并继续往下走。这个过程中,主线程(JavaScript的单线程)会被牢牢占据,直到当前任务全部完成,期间不会处理其他任何任务,同步模式(Synchronous Mode) 是JavaScript 最基础、最直观的代码执行方式。
调用栈(Call Stack)
在 JavaScript 中,调用栈(Call Stack)是 JS 引擎实现同步代码执行的核心数据结构,它遵循 后进先出(LIFO,Last In First Out) 的基本规则,主要作用是记录当前引擎正在执行的函数、执行顺序以及每个函数的执行上下文(包含变量、作用域链、this 指向等关键信息),是理解 JS 同步代码执行流程的关键。
JS 引擎处理同步函数调用时,会遵循 “压栈” 和 “出栈” 两个核心操作:
- 压栈(push):当执行一个函数时,
JS引擎会创建该函数的执行上下文,并将其添加到调用栈的顶部(栈顶)。 - 出栈(pop):当函数执行完毕(包括正常返回或抛出异常),其执行上下文会从调用栈的顶部被移除,引擎继续执行栈顶剩余的上下文。
为什么要有异步模式?
JavaScript 是一种基于原型、多范式、单线程的动态语言,并且支持面向对象、命令式和声明式(如函数式编程)风格。
MDN里对JavaScript的描述提到了很重要的一点特性单线程。
为什么采用单线程模式?
学习前端的时候大家都知道,HTML决定网页的结构,CSS决定网页的样式,JavaScript决定网页的行为。
那么JavaScript如何决定网页的行为呢?
JavaScript 设计初衷是作为浏览器端的脚本语言,核心目标实现页面的动态交互,而实现动态交互的核心就是 DOM操作 ,如果有多个线程同时操作了同一个DOM,我们无法明确应该以哪个线程的操作结果为准,这就决定了它只能使用单线程模式,单线程也就成为了 JavaScript 语言的核心之一。
采用单线程模式的问题?
采用单线程模式,在同步模式下,如果出现耗时的操作(如定时器、网络请求等),就会阻塞程序的执行导致页面卡顿,如果出现异常则会导致页面卡死,这时候就需要用到异步模式了。
异步模式
在 JavaScript 中,异步模式(Asynchronous Mode) 是为解决单线程下同步模式耗时任务阻塞程序执行的问题而设计的代码执行方式,它允许耗时任务在后台执行,主线程无需等待其完成,可继续处理其他任务,待耗时任务结束后,再通过特定机制回调执行结果。这是 JS 实现非阻塞执行的核心,也是前端处理网络请求、定时器、DOM 事件等场景的基础。
异步执行机制
-
任务移交
主线程执行到异步任务(如
setTimeout、AJAX)时,不会等待其完成,而是将该任务移交至浏览器的Web API模块(Node.js中为libuv)进行处理。 -
回调入列
当**
Web API中的异步任务执行完成后,会将回调函数放入对应的任务队列**(分为宏任务队列和微任务队列)中等待执行。 -
回调执行
主线程的调用栈清空(同步代码执行完毕)后,事件循环会从任务队列中取出回调函数,压入调用栈中执行,执行完毕后再次检查队列,循环此过程。
回调函数
回调函数是作为参数传递到另一个函数中,然后在外部函数内调用以完成某种例行程序或操作的函数。
异步编程方案的基础就是利用回调函数去处理异步任务的执行结果。
这里用一个简单的例子讲一下回调函数的作用:
洗衣机洗衣服
你把衣服放进洗衣机,按下启动键(触发异步任务:洗衣机洗衣 + 甩干),这个过程要 40 分钟,你不可能站在洗衣机旁干等(主线程解放,去做别的事:写代码、写博客)。
洗完衣服后我是不是得,把衣服拿去晾晒,但是我又不能干等着,需要等待 “洗完后滴滴响”(这就是洗衣机预设的**回调函数 **)。等 40 分钟后洗衣机洗完衣服(异步任务完成),就会自动滴滴响(执行回调函数),你听到声音后,就去晾衣服。
如果没有 “滴滴响” 这个回调,你要么得一直盯着洗衣机(同步阻塞),要么不知道衣服洗完了,异步任务的结果(衣服洗好了)就没法被处理。
1266

被折叠的 条评论
为什么被折叠?



