备案个人网站名称大全,网页设计模板中国素材,王野天简历,wordpress会员支付系统这是个非常重要的面试 实战知识点#xff1a;浏览器和 Node.js 的事件循环#xff08;Event Loop#xff09;虽然概念相同#xff0c;但机制不同。
我来从本质、宏任务/微任务、I/O处理、多线程差异四方面帮你系统讲清楚它们的区别。
✅ 执行流程总结#xff1a; …这是个非常重要的面试 实战知识点浏览器和 Node.js 的事件循环Event Loop虽然概念相同但机制不同。
我来从本质、宏任务/微任务、I/O处理、多线程差异四方面帮你系统讲清楚它们的区别。
✅ 执行流程总结
1. 先执行所有同步代码主线程代码 所有你直接写在 JS 文件里的代码会立即执行。 包括变量定义、函数调用只要不是异步、require() 等等。
2. 同步代码执行完毕后进入事件循环Event Loop 开始一轮又一轮的事件循环。 每一轮事件循环按六大阶段运行每个阶段中处理对应的异步回调。 所以总结为一句话 Node.js 先执行主线程中的所有同步任务再开始事件循环处理异步任务包括定时器、IO、事件监听等。 ✅ 1. 相同点基本概念一样 都是单线程执行主任务 都使用事件队列 执行栈 回调机制 都支持微任务microtask和宏任务macrotask 2. 不同点事件循环机制差异
特性浏览器Node.js执行环境JavaScript 引擎通常是 V8 浏览器 APIJavaScript 引擎 libuv底层C库宏任务macrotasksetTimeout, setInterval, setImmediate, UI事件等setTimeout, setInterval, setImmediate, I/O, close callbacks微任务microtaskPromise.then, MutationObserver, queueMicrotaskPromise.then, process.nextTick, queueMicrotask微任务优先级Promise.then 是主流process.nextTick Promise.then渲染有 UI 渲染阶段浏览器每帧约 16ms无 UI 渲染逻辑阶段结构比较简单宏任务 - 微任务 - 渲染更复杂6个阶段的 Event Loop 阶段 3. Node.js 的六大阶段基于 libuv
Node.js 的事件循环分为 6个阶段 timers处理 setTimeout 和 setInterval pending callbacks处理某些系统操作的回调 idle, prepare内部专用 poll处理 I/O 事件等待回调 check执行 setImmediate 回调 close callbacks关闭回调如 socket.on(close, ...)
每个阶段结束后会执行微任务队列microtask queueprocess.nextTick 优先于 Promise 微任务执行。 4. 举个区别示例
setTimeout(() console.log(setTimeout), 0);
setImmediate(() console.log(setImmediate));Promise.resolve().then(() console.log(Promise));
process.nextTick(() console.log(nextTick));Node.js 中输出顺序
nextTick
Promise
setTimeout
setImmediate // 注意在文件顶层执行setTimeout 通常先于 setImmediate浏览器中输出顺序
Promise
setTimeout
// setImmediate 是 Node 专有的在浏览器中不存在小结
特性浏览器Node.js微任务顺序Promise 优先process.nextTick Promise渲染机制有 UI 渲染无定时器行为setTimeout 每次都在下一个宏任务setTimeout 在 timers 阶段setImmediate不支持专属check 阶段执行事件循环复杂度简单宏微复杂6阶段 需要我画图对比两者的执行流程或者用一段代码让你调试执行顺序欢迎继续提问。 注意事项 process.nextTick() 总是优先于所有微任务即使是 Promise。 setImmediate() 和 setTimeout(..., 0) 谁先执行取决于调用时的上下文。 每个阶段结束后都会检查微任务队列执行所有微任务后才进入下一个阶段。 二、每一个宏任务执行完毕后立即执行所有微任务队列microtask queue中的任务。 ✅ 每一个宏任务执行完毕后立即执行所有微任务队列microtask queue中的任务。 事件循环中的顺序浏览器端 从宏任务队列中取出一个宏任务执行如 setTimeout、UI 事件、ajax 回调 等 宏任务执行完之后 ➜ 立即执行所有微任务如 Promise.then, queueMicrotask, MutationObserver 微任务队列清空后开始下一轮事件循环Event Loop 举例说明
console.log(script start);setTimeout(() {console.log(setTimeout);
}, 0);Promise.resolve().then(() {console.log(promise1);
}).then(() {console.log(promise2);
});console.log(script end);浏览器中的输出
script start
script end
promise1
promise2
setTimeout✅ script 是第一个宏任务执行完后进入微任务队列再继续下一个宏任务setTimeout。 ✅ 结论总结 每轮事件循环tick中 先执行一个宏任务 再执行所有微任务 然后开始下一轮宏任务 所以微任务的优先级比宏任务高 微任务不会“等所有宏任务执行完才开始”而是“每个宏任务结束之后马上执行”
三、事件循环执行顺序代码练习
首先下面两行代码是无法再浏览器中执行的只能在nodejs环境里执行
setImmediate(() console.log(setImmediate));
process.nextTick(() console.log(nextTick));
现在我来给你一段能在两个环境中都运行但执行顺序不同的代码并详细解释其执行差异。 ✅ 通用代码两个环境都能执行
setTimeout(() {console.log(timeout);
}, 0);Promise.resolve().then(() {console.log(promise);
});queueMicrotask(() {console.log(microtask);
});Node.js 输出顺序
microtask
promise
timeout浏览器输出顺序Chrome, Firefox, Safari 等
microtask
promise
timeout❗看起来一样别急。
我们来用更复杂一点的例子展示 Node.js 和浏览器真实存在的执行差异 关键对比示例代码
setTimeout(() {console.log(setTimeout);
}, 0);Promise.resolve().then(() {console.log(Promise 1);
});Promise.resolve().then(() {console.log(Promise 2);
});console.log(sync);Node.js 输出顺序
sync
Promise 1
Promise 2
setTimeout浏览器输出顺序
sync
Promise 1
Promise 2
setTimeout看似又一样 真正输出顺序不同的代码如下
Promise.resolve().then(() {console.log(Promise);
});setTimeout(() {console.log(timeout);
}, 0);setInterval(() {console.log(interval);process.exit(); // Node 专用
}, 0);在 Node.js 中setInterval 的第一次执行可能比 setTimeout 慢取决于事件循环 timing。 而在 浏览器中setInterval 和 setTimeout 都在宏任务中但执行间隔由定时器精度控制最小为 4ms。
但你要求的是更典型的 终极演示顺序不同的通用代码
setTimeout(() console.log(timeout), 0);Promise.resolve().then(() console.log(promise));console.log(sync);✅ 浏览器输出
sync
promise
timeout✅ Node.js 输出一样
sync
promise
timeout那到底如何展示 顺序不同
我们需要 Node 专有函数 setImmediate 来区别 真正有区别的对比代码只能在 Node.js 和浏览器区分
setTimeout(() console.log(setTimeout), 0);setImmediate?.(() console.log(setImmediate));Promise.resolve().then(() console.log(Promise));queueMicrotask(() console.log(Microtask));console.log(sync);✅ Node.js 输出常见
sync
Microtask
Promise
setTimeout
setImmediate✅ 浏览器输出
浏览器没有 setImmediate所以会报错或忽略
sync
Microtask
Promise
setTimeout总结
操作类型Node.js 优先级浏览器优先级console.log同步任务同步任务process.nextTick微任务队列最前比 Promise 更早❌ 不存在queueMicrotask微任务队列中微任务队列中Promise.then微任务队列中微任务队列中setTimeout宏任务timers阶段宏任务setImmediatecheck阶段的宏任务晚于 setTimeout❌ 不存在
如果你写的 JavaScript 代码只使用浏览器和 Node.js 都支持的 API如 setTimeout、Promise、queueMicrotask 等那么它们的执行顺序在两者之间基本是没有区别的原因如下
❗只有使用 Node.js 专有 API顺序才可能发生变化
Node.js 专有 API浏览器支持是否会造成执行顺序不同process.nextTick()❌ 不支持✅ 会优先级最高setImmediate()❌ 不支持✅ 会晚于 setTimeout ✅ 举个真实差异例子只在 Node.js 有
setTimeout(() {console.log(setTimeout);
}, 0);setImmediate(() {console.log(setImmediate);
});在 Node.js 中 有时输出顺序是 setTimeout
setImmediate有时是 setImmediate
setTimeout取决于当前事件循环阶段极其敏感
在浏览器中 setImmediate 根本不存在会报错或被忽略。 ✅ 浏览器和 Node.js 都支持的任务类别
任务类型优先级支持环境示例代码同步任务最高浏览器 Nodeconsole.log(sync)微任务Promise高浏览器 NodePromise.resolve().then(...)微任务queueMicrotask高浏览器 NodequeueMicrotask(...)宏任务setTimeout低浏览器 NodesetTimeout(..., 0) 如果你不使用 Node.js 特有的 API如 process.nextTick、setImmediate你的代码在浏览器和 Node.js 中的执行顺序基本是一样的。 要对比事件循环机制的差异必须涉及到 Node.js 独有的任务调度机制。如果你需要可视化事件循环对比图我可以马上生成一张图来帮助你更直观理解。是否需要 如果你希望我给出一张图来说明「浏览器 vs Node.js 事件循环对比图」我可以画一个视觉化的流程。是否需要
四、NodeJS11和10以及之前的事件循环执行差异
版本微任务执行时机Node.js ≤10所有宏任务执行完后统一跑微任务Node.js ≥11每个宏任务后立即跑一次微任务队列
Node.js 不同版本的事件循环行为确实是有差异的尤其体现在宏任务执行后的微任务调度时机这一点上Node 10 与 Node 11尤其是 Node 11.0.0 到 11.1.0之间存在关键差别。以下是完整解释 ✅ 1. Node.js 中事件循环阶段回顾
Node.js 事件循环分为 6 个阶段 timers定时器如 setTimeout, setInterval pending callbacks idle, prepare poll checksetImmediate close callbacks
微任务microtasks 包括 process.nextTickNode 专有优先级高于所有微任务 Promise.then、queueMicrotaskECMAScript 标准微任务 ✅ 2. Node.js 不同版本的行为差异对比 Node 10 及之前版本
在 timers 阶段如果定时器回调队列中有多个任务先执行完所有这些任务再执行一次微任务队列。 所以所有 setTimeout 执行完 → 再跑一次微任务队列。 Node 11尤其从 v11.0.0 开始
Node 11 引入了浏览器类似的行为 每执行一个宏任务例如一个定时器回调就执行一次微任务队列也就是 setTimeout 1 → microtasks → setTimeout 2 → microtasks ...
这种行为更贴近浏览器的事件循环机制。 ✅ 3. 举个例子对比
setTimeout(() {console.log(timeout1);Promise.resolve().then(() console.log(promise1));
}, 0);setTimeout(() {console.log(timeout2);Promise.resolve().then(() console.log(promise2));
}, 0);在 Node 10
timeout1
timeout2
promise1
promise2在 Node 11
timeout1
promise1
timeout2
promise2✅ 4. 总结Node.js 中宏任务执行后微任务处理机制的版本演化
Node.js 版本宏任务后微任务调度行为类似于浏览器≤ v10所有宏任务执行完 → 再统一执行微任务队列❌ 否v11含每个宏任务执行完后 → 立即执行微任务队列✅ 是v16现代主流保持浏览器兼容行为符合 Promises/A 规范✅ 是 查看当前 Node.js 版本
你可以运行
node -v查看当前版本以决定代码执行行为。