Node.js
发布时间:2022-04-24 发布网站:大佬教程 code.js-code.com
大佬教程收集整理的这篇文章主要介绍了理解 Node.js 的 Event loop,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
问题 考察如下代码,脑回路中运行并输出结果:
console.log("1");
setTimeout(function setTimeout1() {
console.log("2");
process.nextTick(function nextTick1() {
console.log("3");
});
new Promise(function promise1(resolve) {
console.log("4");
resolve();
}).then(function promisethen1() {
console.log("5");
});
setImmediate(function immediate1() {
console.log("immediate");
});
});
process.nextTick(function nextTick2() {
console.log("6");
});
function bar() {
console.log("bar");
}
async function foo() {
console.log("async start");
await bar();
console.log("async end");
}
foo();
new Promise(function promise2(resolve) {
console.log("7");
resolve();
}).then(function promisethen2() {
console.log("8");
});
setTimeout(function setTimeout2() {
console.log("9");
new Promise(function promise3(resolve) {
console.log("11");
resolve();
}).then(function promisethen3() {
console.log("12");
});
process.nextTick(function nextTick3() {
console.log("10");
});
});
JS 事件循环 JS 是单线程,朴素地讲,同时只能完成一件事件。如果有耗时的任务,那后续的所有任务都要等待其完成才能执行。 为了避免这种阻塞,引入了事件循环。即,将代码的执行分成一个个很小的阶段(一次循环),每个阶段重复相应的事情,直到所有任务都完成。 一个阶段包含以下部分:
- Timers:到期的定时器任务,
setTimeout@H_851_301@,seTinterval@H_851_301@ 等注册的任务。
- IO CallBACks:IO 操作,比如网络请求,文件读写。
- IO Polling:IO 任务的注册
- Set Immediate:通过
setImmediate@H_851_301@ 注册的任务
- Close:
close@H_851_301@ 事件的回调,比如 TCP 的断开。
Ticks and Phases of the Node.js Event Loop 图片来自 Daniel Khan 的 Medium 博客,见文末 同步代码及上面每个环节结束时都会清空一遍微任务队列,记住这点很重要! 执行的流程是,
- 将代码顺序执行。
- 遇到异步任务,将任务压入待执行队列后继续往下。
- 完成同步代码后,检查是否有微任务(通过
Promise@H_851_301@,process.nextTick@H_851_301@,async/await@H_851_301@ 等注册),如果有,则清空。
- 清空微任务队列后,从待执行队列中取出最先压入的任务顺序执行,重复步骤一。
另,
-
async/await@H_851_301@ 本质上是 Promise@H_851_301@,所以其表现会和 Promise 一致。
-
process.nextTick@H_851_301@ 注册的回调优先级高于定时器。
-
setImmediate@H_851_301@ 可看成 Node 版本的 setTimeout@H_851_301@,所以可与后者同等对待。
Round 1
- 首先遇到同步代码
console.log(1)@H_851_301@,立即执行输出 1@H_851_301@
- 接下来是一个
setTimeout@H_851_301@ 定时器,将其回调压入待执行队列 [setTimeout1]@H_851_301@
- 遇到
process.nextTick@H_851_301@,将其回调 nextTick2@H_851_301@ 压入微任务队列 [nextTick2]@H_851_301@
- 然后是 async 函数
foo@H_851_301@ 的调用,立即执行并输出 async start@H_851_301@
- 然后是
await@H_851_301@ 语句,这所在的地方会创建并返回 Promise,所以这里会执行其后面的表达式,也就是 bar()@H_851_301@ 函数的调用。
- 执行
bar@H_851_301@ 函数,输出 bar@H_851_301@
- 在执行了
await @H_851_301@ 后面的语句后,它所代表的 Promise 就创建完成了,foo@H_851_301@ 函数体后续的代码相当于 promise 的 then@H_851_301@,放入微任务队列 [nextTick2,rest_of_foo]@H_851_301@
- 继续往下遇到
new Promise@H_851_301@,执行 Promise 的创建输出 7@H_851_301@,将它的 then@H_851_301@ 回调压入微任务队列 [nextTick2,rest_of_foo,promisethen2]@H_851_301@
- 遇到另一个
setTimeout@H_851_301@,回调压入待执行队列 [setTimeout1,setTimeout2]@H_851_301@
- 至此,代码执行完了一轮。此时的输出应该是
1,async start,bar,7@H_851_301@
Round 2
- 查看微任务队列,并清空。所以依次执行
[nextTick2,promisethen2]@H_851_301@,输出 6,async end,8@H_851_301@。
Round 3
- 查看待执行队列
[setTimeout1,setTimeout2]@H_851_301@,先执行 setTimout1@H_851_301@
- 遇到
console.log(2)@H_851_301@ 输出2
- 遇到
process.nextTick@H_851_301@ 将 nextTick1@H_851_301@ 压入微任务队列 [nextTick1]@H_851_301@
- 遇到
new Promise@H_851_301@ 立即执行 输出 4@H_851_301@,执行 resolve()@H_851_301@ 后将 promisethen1@H_851_301@ 压入微任务队列 [nextTick1,promisethen1]@H_851_301@
- 遇到
setImmediate@H_851_301@ 将回调压入待执行队列 [setTimeout2,immediate1]@H_851_301@
- 此时
setTimeout1@H_851_301@ 执行完毕,此时的输出应该为 2,4@H_851_301@
Round 4
- 检查微任务队列
[nextTick1,promisethen1]@H_851_301@ 依次执行并输出 3,5@H_851_301@
Round 5
- 检查待执行队列
[setTimeout2,immediate1]@H_851_301@,执行 setTimeout2@H_851_301@
- 遇到
console@H_851_301@输出 9@H_851_301@
- 遇到
new Promise@H_851_301@ 执行并输出 11@H_851_301@,将 promisethen3@H_851_301@ 压入微任务队列 [promisethen3]@H_851_301@
- 遇到
process.nextTick@H_851_301@ 将 nextTick3@H_851_301@ 压入微执行队列。注意,因为 process.nextTick@H_851_301@ 的优化级高于 Promise,所以压入后的结果是: [nextTick3,promisethen3]@H_851_301@
- 此时
setTimeout2@H_851_301@ 执行完毕,输出为 9,11@H_851_301@
Round 6
- 检查微任务队列
[nextTick3,promisethen3]@H_851_301@ 执行并输出 10,12@H_851_301@
Round 7
- 检查待执行队列
[immediate1]@H_851_301@,执行并输出 immediate@H_851_301@
至此,走完了所有代码。 结果 以下是文章开头的结果:
1
async start
bar
7
6
async end
8
2
4
3
5
9
11
10
12
immediate
|
大佬总结
以上是大佬教程为你收集整理的理解 Node.js 的 Event loop全部内容,希望文章能够帮你解决理解 Node.js 的 Event loop所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。