JavaScript 的执行机制
JavaScript 作为一门单线程、非阻塞的脚本语言,其执行机制是理解其运行原理的核心,要深入探讨 JavaScript 怎么执行,需要从调用栈、任务队列、事件循环等关键概念入手,并结合代码实例分析其执行流程。

调用栈与同步执行
JavaScript 的执行环境是调用栈(Call Stack),它遵循“后进先出”(LIFO)的原则,当函数被调用时,它会被推入调用栈;函数执行完毕后,从栈顶弹出。
function foo() {
console.log('foo');
}
function bar() {
foo();
}
bar();
执行时,bar() 先入栈,调用 foo() 后 foo() 入栈,foo() 执行完毕弹出,bar() 继续执行后弹出,这个过程是同步的,即代码按顺序逐行执行,前一个任务完成后才能执行下一个任务。
异步任务与任务队列
JavaScript 的单线程特性意味着它无法同时处理多个任务,但通过异步机制(如回调、Promise、async/await)可以实现非阻塞执行,异步任务不会立即进入调用栈,而是被分为宏任务(Macrotask)和微任务(Microtask),分别进入不同的任务队列。

- 宏任务:包括整体代码脚本、
setTimeout、setInterval、I/O操作、UI 渲染等。 - 微任务:包括
Promise.then/catch/finally、MutationObserver、async/await的后续操作等。
事件循环的执行流程
事件循环(Event Loop)是连接调用栈与任务队列的桥梁,其核心流程如下:
- 执行同步代码:调用栈中的同步任务按顺序执行。
- 执行微任务队列:同步代码执行完毕后,检查微任务队列,按顺序执行所有微任务,直到微任务队列为空。
- 执行宏任务队列:从宏任务队列中取出一个任务(通常是整体代码或
setTimeout等)放入调用栈执行。 - 重复步骤 2-3:每次宏任务执行完毕后,都会清空微任务队列,再取下一个宏任务,形成循环。
console.log('1'); // 同步任务
setTimeout(() => console.log('2'), 0); // 宏任务
Promise.resolve().then(() => console.log('3')); // 微任务
console.log('4'); // 同步任务
执行顺序为:
- 同步代码
console.log('1')和console.log('4')先执行,输出1和4。 - 微任务队列中的
Promise.then执行,输出3。 - 宏任务队列中的
setTimeout执行,输出2。
最终输出顺序为 1、4、3、2。

异步代码的执行细节
setTimeout的延迟时间:setTimeout(fn, 0)并非立即执行,而是将fn推入宏任务队列,需等待当前同步代码和微任务队列执行完毕。Promise的微任务特性:Promise的状态一旦改变,后续的.then等回调会被推入微任务队列,优先级高于宏任务。async/await的本质:async函数返回一个Promise,await会暂停函数执行,等待Promise解决后,将后续代码推入微任务队列。
JavaScript 的执行机制围绕事件循环展开,同步任务优先执行,随后清空微任务队列,再执行宏任务队列中的任务,这种机制确保了单线程下的高效执行,同时通过异步任务处理非阻塞操作,理解调用栈、任务队列和事件循环的协同工作原理,对于编写高效、可预测的 JavaScript 代码至关重要,在实际开发中,合理利用异步机制可以避免阻塞主线程,提升用户体验。

















