一、是什么

浏览器事件循环中,我们了解到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

参考文献

  • https://segmentfault.com/a/1190000012258592

Node.js 中的事件循环机制的更多相关文章

  1. node.js中的事件循环机制

    http://www.cnblogs.com/dolphinX/p/3475090.html

  2. 【nodejs原理&源码赏析(7)】【译】Node.js中的事件循环,定时器和process.nextTick

    [摘要] 官网博文翻译,nodejs中的定时器 示例代码托管在:http://www.github.com/dashnowords/blogs 原文地址:https://nodejs.org/en/d ...

  3. 【nodejs原理&源码赏析(7)】【译】Node.js中的事件循环,定时器和process.nextTick

    目录 Event Loop 是什么? Event Loop 基本解释 事件循环阶段概览 事件循环细节 timers pending callbacks poll阶段 check close callb ...

  4. JavaScript中的事件循环机制跟函数柯里化

    一.事件循环机制的理解 test();//按秒输出5个5 function test() { for (var i = 0; i < 5; i++) { setTimeout(() => ...

  5. 初步揭秘node.js中的事件

    当你学习node.js的时候,Events是一个非常重要的需要理解的事情.非常多的Node对象触发事件,你能在文档API中找到很多例子.但是关于如何写自己的事件和监听,你可能还不太清楚.如果你不了解, ...

  6. node.js中的事件轮询Event Loop

    任务队列/事件队列 "任务队列"是一个事件的队列,IO设备完成一项任务,就在"任务队列"中添加一个事件,表示相关的异步任务可以进入"执行栈" ...

  7. js中的事件缓存机制

    异步任务指的是,不进入主线程.而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行. ...

  8. js高级-浏览器事件循环机制Event Loop

    JavaScript 是队列的形式一个个执行的 同一时间只能执行一段代码,单线程的  (队列的数据结构) 浏览器是多线程的 JavaScript执行线程负责执行js代码 UI线程负责UI展示的 Jav ...

  9. Node.js中模块加载机制

    1.模块查找规则-当模块拥有路径但没有后缀时:(require(‘./find’)) require方法根据模块路径查找模块,如果是完整路径,直接引入模块: 如果模块后缀省略,先找同名JS文件,再找同 ...

  10. node.js 中模块的循环调用问题详解

    首先,我们看一下图示代码,每一个注释其实代表一个 js 文件.所以下面其实是三个 js 文件 .第一个是我们要运行的 main 文件,后面两个是 a, b 文件.   从上面可以看书 a ,b 两个模 ...

随机推荐

  1. Java基础全程复习笔记(值得参考)

    Java基础复习笔记 第01章:Java语言概述 1. Java基础学习的章节划分 第1阶段:Java基本语法 Java语言概述.Java的变量与进制.运算符.流程控制语句(条件判断.循环结构).br ...

  2. Socket编程:htons()、htonl()、ntohs()、ntohl()

    前言 在计算机网络学到Socket编程的时候,自己在Linux下用C语言试验了一番,发现了这四个古怪的函数:htons().htonl().ntohs().ntohl(). 查阅资料得知,这是涉及到网 ...

  3. end_of_line = lf 选择行尾序列 .editorconfig - 老项目不动代码存盘 文件变动 CRLF 的问题 vscode

    end_of_line = lf 选择行尾序列 .editorconfig - 老项目不动代码存盘 文件变动 CRLF 的问题 缘由 vscode 老项目代码,没有变动,ctrl + s后 文件有变化 ...

  4. vscode sftp 代码同步到服务器

    然后执行 ctrl+shift+p ,搜索 SFTP:Config 回车后,会生成一个".vscode/sftp.json",这个就是配置文件 参考:VsCode SFTP插件详细 ...

  5. 「AntV」路网数据获取与L7可视化

    1. 引言 L7 地理空间数据可视分析引擎是一种基于 WebGL 技术的地理空间数据可视化引擎,可以用于实现各种地理空间数据可视化应用.L7 引擎支持多种数据源和数据格式,包括 GeoJSON.CSV ...

  6. 记录--前端如何优雅导出多表头xlsx

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前言 xlsx导出是比较前后端开发过程中都比较常见的一个功能.但传统的二维表格可能很难能满足我们对业务的需求,因为当数据的维度和层次比较多 ...

  7. 记录--微信小程序,uniapp,H5端发送,显示emoji表情

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 小伙伴们,在开发中有没有遇到过发布帖子或者实时聊天需要发送到一些emoji表情的. 但是每当我们直接将emoji表情提交到后台的接口又会报 ...

  8. Python 如何通过网易163邮箱自动发送邮件

    一.发送邮件的前提是必须开通发件服务器获取对应授权密码. 二.对应代码如下所示 import smtplib from email.mime.text import MIMEText from ema ...

  9. .NET分布式Orleans - 2 - Grain的通信原理与定义

    Grain 是 Orleans 框架中的基本单元,代表了应用程序中的一个实体或者一个计算单元. 每个Silo都是一个独立的进程,Silo负责加载.管理和执行Grain实例,并处理来自客户端的请求以及与 ...

  10. RelationNet:学习目标间关系来增强特征以及去除NMS | CVPR 2018

    论文基于NLP的注意力机制提出了目标关系模块,通过与其它目标的比对增强当前目标的特征,而且还可以代替NMS进行端到端的重复结果去除,思想十分新颖,效果也不错   来源:晓飞的算法工程笔记 公众号 论文 ...