JavaScript是单线程、基于事件循环的解释型语言,核心在于call stack、Web APIs、task queue和microtask queue协同调度同步与异步任务,宏任务与微任务优先级不同,且Event Loop由宿主环境实现。

JavaScript 是单线程、基于事件循环(Event Loop)的解释型语言,它的执行机制核心不在于“多任务并行”,而在于“如何协调同步代码、异步回调与任务调度”。理解它,关键不是背概念,而是看清 call stack、Web APIs、task queue 和 microtask queue 四者怎么协作。
同步代码怎么一步步执行:call stack 是唯一真相
所有同步函数调用都压入 call stack,后进先出。一旦某函数抛错或返回,它立刻弹出;栈空了,JS 引擎才继续看下一步该做什么。
常见误解是以为 setTimeout 或 Promise 会“中断”当前执行——其实不会。它们只是把回调注册出去,自己立刻返回,不阻塞栈。
-
call stack永远只跑同步逻辑,没有“暂停”“切片”概念 - 递归过深直接触发
RangeError: Maximum call stack size exceeded -
await看似停顿,实际是语法糖:遇到await后,函数立即退出(返回Promise),后续逻辑被编译成微任务塞进microtask queue
异步回调分两类:macro task 和 micro task 的优先级差异
不是所有异步回调都一样。JS 规范明确区分了宏任务(macro task)和微任务(micro task),执行顺序直接影响结果。
立即学习“Java免费学习笔记(深入)”;
典型 macro task:setTimeout、setInterval、setImmediate(Node.js)、I/O 回调;
典型 micro task:Promise.then/catch/finally、queueMicrotask、MutationObserver 回调。
可编程序控制器,英文称Programmable Controller,简称PC。但由于PC容易和个人计算机(Personal Computer)混淆,故人们仍习惯地用PLC作为可编程序控制器的缩写。它是一个以微处理器为核心的数字运算操作的电子系统装置,专为在工业现场应用而设计,它采用可编程序的存储器,用以在其内部存储执行逻辑运算、顺序控制、定时/计数和算术运算等操作指令,并通过数字式或模拟式的输入、输出接口,控制各种类型的机械或生产过程。本平台提供PLC编程入门基础知识下载,需要的朋友们下载看看吧!
- 每次
call stack清空后,引擎先执行所有 microtask(直到队列为空),再取一个 macro task 执行 - 这意味着连续的
Promise.resolve().then(...)会比紧挨着的setTimeout(..., 0)先运行 - Node.js 中
process.nextTick()属于 microtask,但优先级高于Promise回调(仅限 Node)
浏览器环境里 Web APIs 怎么参与执行流程
JS 引擎本身不处理定时器、HTTP 请求或 DOM 事件——这些由浏览器的 Web APIs 模块接管。JS 只负责注册回调,然后继续往下跑。
例如:setTimeout(() => console.log('A'), 0) 被调用时,JS 引擎把回调交给 Timer 系统,自己立刻返回;等 Timer 到时,回调被推入 macro task 队列,等待下一轮 Event Loop 处理。
- DOM 事件(如
click)触发后,事件处理函数作为 macro task 进入队列 -
fetch()的.then()是 micro task;但fetch()本身发起请求是同步的,不等待响应 - Web Workers 是真正的多线程,但主线程与 Worker 之间只能通过
postMessage通信,消息处理仍是 Event Loop 机制
为什么 await + Promise.resolve() 不等于同步执行
很多人写 await Promise.resolve(42) 以为能“立刻拿到值”,但其实它仍会跳出当前函数、清空栈、再以微任务形式恢复执行。
console.log(1); await Promise.resolve(); console.log(2); // 输出:1 → (中间有微任务调度)→ 2 // 并非“同步连续打印”,中间可能穿插其他 microtask
-
await总是导致函数退出并返回 pendingPromise,哪怕右边是已 resolve 的值 - 想真正同步执行,就别用
await;想模拟“同步感”,得靠try/catch+Promise链式错误传递,而非消灭异步性 - 在 React 等框架中滥用
await在渲染函数里,会导致组件挂起或状态不一致,因为渲染必须是同步且可中断的
最常被忽略的一点:Event Loop 不是 JS 引擎的私有机制,而是宿主环境(浏览器/Node)定义的协调协议。V8 只管执行 JS 代码、管理栈和 Promise 状态;谁来轮询队列、何时触发 timer、怎么调度 I/O——全由宿主决定。这也解释了为什么同一段代码,在浏览器和 Node 中的 microtask 执行时机可能略有差异。









