node.js事件循环机制及与js区别详解

 更新时间:2022年09月26日 09:24:02   作者:别救了这猴子废了  
这篇文章主要为大家介绍了node.js事件循环机制及与js区别详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

一、是什么

浏览器事件循环(opens new window)中,我们了解到javascript在浏览器中的事件循环机制,其是根据HTML5定义的规范来实现

而在NodeJS中,事件循环是基于libuv实现,libuv是一个多平台的专注于异步IO的库,如下图最右侧所示:

上图EVENT_QUEUE 给人看起来只有一个队列,但EventLoop存在6个阶段,每个阶段都有对应的一个先进先出的回调队列

二、流程

上节讲到事件循环分成了六个阶段,对应如下:

  • timers阶段:这个阶段执行timer(setTimeout、setInterval)的回调
  • 定时器检测阶段(timers):本阶段执行 timer 的回调,即 setTimeout、setInterval 里面的回调函数
  • I/O事件回调阶段(I/O callbacks):执行延迟到下一个循环迭代的 I/O 回调,即上一轮循环中未被执行的一些I/O回调
  • 闲置阶段(idle, prepare):仅系统内部使用
  • 轮询阶段(poll):检索新的 I/O 事件;执行与 I/O 相关的回调(几乎所有情况下,除了关闭的回调函数,那些由计时器和 setImmediate() 调度的之外),其余情况 node 将在适当的时候在此阻塞
  • 检查阶段(check):setImmediate() 回调函数在这里执行
  • 关闭事件回调阶段(close callback):一些关闭的回调函数,如:socket.on('close', ...)

每个阶段对应一个队列,当事件循环进入某个阶段时, 将会在该阶段内执行回调,直到队列耗尽或者回调的最大数量已执行, 那么将进入下一个处理阶段

除了上述6个阶段,还存在process.nextTick,其不属于事件循环的任何一个阶段,它属于该阶段与下阶段之间的过渡, 即本阶段执行结束, 进入下一个阶段前, 所要执行的回调,类似插队

流程图如下所示:

Node中,同样存在宏任务和微任务,与浏览器中的事件循环相似

微任务对应有:

  • next tick queue:process.nextTick
  • other queue:Promise的then回调、queueMicrotask

宏任务对应有:

  • timer queue:setTimeout、setInterval
  • poll queue:IO事件
  • check queue:setImmediate
  • close queue:close事件

其执行顺序为:

  • next tick microtask queue
  • other microtask queue
  • timer queue
  • poll queue
  • check queue
  • close queue

三、题目

通过上面的学习,下面开始看看题目

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 队列中
  • 遇到第二个 setTimeout,300ms后将里面的回调函数放到 timer 队列中
  • 遇到第一个setImmediate,将里面的回调函数放到 check 队列中
  • 遇到第一个 nextTick,将其里面的回调函数放到本轮同步任务执行完毕后执行
  • 执行 async1函数,输出 async1 start
  • 执行 async2 函数,输出 async2,async2 后面的输出 async1 end进入微任务,等待下一轮的事件循环
  • 遇到第二个,将其里面的回调函数放到本轮同步任务执行完毕后执行
  • 遇到 new Promise,执行里面的立即执行函数,输出 promise1、promise2
  • then里面的回调函数进入微任务队列
  • 遇到同步任务,输出 script end
  • 执行下一轮回到函数,先依次输出 nextTick 的函数,分别是 nextTick1、nextTick2
  • 然后执行微任务队列,依次输出 async1 end、promise3
  • 执行timer 队列,依次输出 setTimeout0
  • 接着执行 check 队列,依次输出 setImmediate
  • 300ms后,timer 队列存在任务,执行输出 setTimeout2

执行结果如下:

script start
async1 start
async2
promise1
promise2
script end
nextTick1
nextTick2
async1 end
promise3
setTimeout0
setImmediate
setTimeout2

最后有一道是关于setTimeoutsetImmediate的输出顺序

setTimeout(() => {
  console.log("setTimeout");
}, 0);
setImmediate(() => {
  console.log("setImmediate");
});

输出情况如下:

情况一:
setTimeout
setImmediate

情况二:
setImmediate
setTimeout

分析下流程:

  • 外层同步代码一次性全部执行完,遇到异步API就塞到对应的阶段
  • 遇到setTimeout,虽然设置的是0毫秒触发,但实际上会被强制改成1ms,时间到了然后塞入times阶段
  • 遇到setImmediate塞入check阶段
  • 同步代码执行完毕,进入Event Loop
  • 先进入times阶段,检查当前时间过去了1毫秒没有,如果过了1毫秒,满足setTimeout条件,执行回调,如果没过1毫秒,跳过
  • 跳过空的阶段,进入check阶段,执行setImmediate回调

这里的关键在于这1ms,如果同步代码执行时间较长,进入Event Loop的时候1毫秒已经过了,setTimeout先执行,如果1毫秒还没到,就先执行了setImmediate

以上就是node.js事件循环机制及与js区别详解的详细内容,更多关于node.js事件循环与js区别的资料请关注脚本之家其它相关文章!

相关文章

  • node + multer 实现文件上传过程

    node + multer 实现文件上传过程

    这篇文章主要介绍了node + multer 实现文件上传过程,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09
  • node.js 实现手机号验证码登录功能

    node.js 实现手机号验证码登录功能

    这篇文章主要介绍了node.js 实现手机号验证码登录功能,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-08-08
  • Node连接MySQL并封装其增删改查的实现代码

    Node连接MySQL并封装其增删改查的实现代码

    本文主要介绍了Node连接MySQL并封装其增删改查的实现代码,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • Nodejs核心模块之net和http的使用详解

    Nodejs核心模块之net和http的使用详解

    net和http模块都是node核心模块之一,他们都可以搭建自己的服务端和客户端,以响应请求和发送请求。这篇文章主要介绍了Nodejs核心模块之net和http的使用详解,感兴趣的小伙伴们可以参考一下
    2019-04-04
  • Node连接mysql数据库方法介绍

    Node连接mysql数据库方法介绍

    本篇文章主要介绍了Node连接mysql数据库方法介绍。详细的介绍了怎样连接和操作数据库,并举例说明,有兴趣的可以了解一下。
    2017-02-02
  • Nest.js参数校验和自定义返回数据格式详解

    Nest.js参数校验和自定义返回数据格式详解

    这篇文章主要给大家介绍了关于Nest.js参数校验和自定义返回数据格式的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • node.js中的path.basename方法使用说明

    node.js中的path.basename方法使用说明

    这篇文章主要介绍了node.js中的path.basename方法使用说明,本文介绍了path.basename的方法说明、语法、使用实例和实现源码,需要的朋友可以参考下
    2014-12-12
  • NodeJs入门教程之定时器和队列

    NodeJs入门教程之定时器和队列

    这篇文章主要给大家介绍了关于NodeJs入门教程之定时器和队列的相关资料,文中通过示例代码以及图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-03-03
  • 前端自动化开发之Node.js的环境搭建教程

    前端自动化开发之Node.js的环境搭建教程

    这篇文章主要介绍了前端自动化开发之Node.js环境搭建的相关资料,文中介绍的非常详细,对大家学习或者使用node.js具有一定的参考价值,需要的朋友们下面来一起看看吧。
    2017-04-04
  • nodejs之koa2请求示例(GET,POST)

    nodejs之koa2请求示例(GET,POST)

    本篇文章主要介绍了nodejs之koa2请求示例(GET,POST),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-08-08

最新评论