Open linwu-hi opened 1 year ago
在Node.js中,事件循环是基于libuv实现的。libuv是一个多平台的专注于异步IO的库,负责处理底层的事件循环和IO操作,使得Node.js能够实现非阻塞的IO。
事件循环主要是为了处理异步操作。在Node.js中,几乎所有的IO操作都是异步的,包括文件读写、网络请求等。为了能够在异步操作完成后及时执行相应的回调函数,Node.js引入了事件循环机制。
Node.js的事件循环是基于事件触发器的概念。事件触发器可以添加监听器,当特定事件发生时,触发相应的回调函数。事件循环不断地检查事件触发器是否有待处理的事件,如果有,则执行相应的回调函数。
事件循环的流程可以简化为以下几个步骤:
Node.js的事件循环分为6个阶段,每个阶段都有对应的任务队列。事件循环每次遍历一个阶段,都会依次执行该阶段的任务队列中的任务。下面是Node.js事件循环的6个阶段:
题目代码如下:
async function async1() { console.log('async1 start') await async2() console.log('async1 end') } async function async2() { console.log('async2') } console.log('script start') setTimeout(function () { console.log('setTimeout0') }, 0) setTimeout(function () { console.log('setTimeout2') }, 300) setImmediate(() => console.log('setImmediate')); process.nextTick(() => console.log('nextTick1')); async1(); process.nextTick(() => console.log('nextTick2')); new Promise(function (resolve) { console.log('promise1') resolve(); console.log('promise2') }).then(function () { console.log('promise3') }) console.log('script end')
分析过程如下:
script start
setTimeout
timer
setImmediate
check
process.nextTick
async1()
async1 start
async2()
async2
new Promise
promise1
promise2
then
console.log('script end')
script end
nextTick1
nextTick2
async1 end
promise3
setTimeout0
setTimeout2
最终输出结果为:
script start async1 start async2 promise1 promise2 script end nextTick1 nextTick2 async1 end promise3 setTimeout0 setImmediate setTimeout2
最后还有一个关于setTimeout与setImmediate的输出顺序的问题。
setTimeout(() => { console.log("setTimeout"); }, 0); setImmediate(() => { console.log("setImmediate"); });
可能输出情况有两种:
情况一
:
setTimeout setImmediate
情况二:
setImmediate setTimeout
这是因为setTimeout的回调函数虽然设置了0毫秒的延迟,但是实际上会被强制改成1ms,而setImmediate会在检查阶段(check阶段)立即执行。因此,如果同步代码执行时间较长,可能会导致setTimeout的回调在setImmediate之后执行。
面试官:说说对Nodejs中的事件循环机制理解?
一、什么是事件循环?
在Node.js中,事件循环是基于libuv实现的。libuv是一个多平台的专注于异步IO的库,负责处理底层的事件循环和IO操作,使得Node.js能够实现非阻塞的IO。
事件循环主要是为了处理异步操作。在Node.js中,几乎所有的IO操作都是异步的,包括文件读写、网络请求等。为了能够在异步操作完成后及时执行相应的回调函数,Node.js引入了事件循环机制。
二、事件循环的流程
Node.js的事件循环是基于事件触发器的概念。事件触发器可以添加监听器,当特定事件发生时,触发相应的回调函数。事件循环不断地检查事件触发器是否有待处理的事件,如果有,则执行相应的回调函数。
事件循环的流程可以简化为以下几个步骤:
三、事件循环的阶段
Node.js的事件循环分为6个阶段,每个阶段都有对应的任务队列。事件循环每次遍历一个阶段,都会依次执行该阶段的任务队列中的任务。下面是Node.js事件循环的6个阶段:
四、题目分析
题目代码如下:
分析过程如下:
script start
。setTimeout
,将其回调函数放入timer
阶段。setTimeout
,设置了300ms后放入timer
阶段。setImmediate
,放入check
阶段。process.nextTick
,放入微任务队列。async1()
,输出async1 start
,然后执行async2()
,输出async2
,async2
后面的代码进入微任务队列,等待下一轮事件循环。process.nextTick
,放入微任务队列。new Promise
,输出promise1
,然后执行立即执行函数,输出promise2
,接着then
的回调进入微任务队列。console.log('script end')
,输出script end
。nextTick1
、nextTick2
、async1 end
、promise3
。timer
阶段,输出setTimeout0
。check
阶段,输出setImmediate
。timer
阶段有任务,输出setTimeout2
。最终输出结果为:
五、setTimeout与setImmediate的输出顺序
最后还有一个关于
setTimeout
与setImmediate
的输出顺序的问题。可能输出情况有两种:
情况一
:
情况二:
这是因为
setTimeout
的回调函数虽然设置了0毫秒的延迟,但是实际上会被强制改成1ms,而setImmediate
会在检查阶段(check
阶段)立即执行。因此,如果同步代码执行时间较长,可能会导致setTimeout
的回调在setImmediate
之后执行。