从一个例子理解NodeJS的事件循环

例子

首先从一个例子开始nodejs的事件循环

const { readFile } = require('fs')
const { resolve } = require('path')
const EventEmitter = require('events')

class EE extends EventEmitter {}

const instance = new EE()

instance.on('jhs', () => {
  console.log('jhs事件回调调用')
})

setTimeout(() => {
  console.log('0 ms 后到期执行的定时器回调')
}, 0)

setTimeout(() => {
  console.log('100 ms 后到期执行的定时器回调')
}, 100)

setTimeout(() => {
  console.log('200 ms 后到期执行的定时器回调')
}, 200)

readFile(resolve(__dirname, '../package.json'), 'utf-8', () => {
  console.log('第1次读取文件操作回调')
})

readFile(resolve(__dirname, '../README.md'), 'utf-8', () => {
  console.log('第2次读取文件操作回调')
})

setImmediate(() => {
  console.log('immediate 立即回调')
})

process.nextTick(() => {
  console.log('process.nextTick 的第 1 次回调')
})

Promise.resolve().then(() => {
  instance.emit('jhs')
  process.nextTick(() => {
    console.log('process.nextTick 的第 2 次回调')
  })
  console.log('promise的第 1 次回调')
}).then(() => {
  console.log('promise的第 2 次回调')
})
  1. 参考下官网的The Node.js Event Loop, Timers, and process.nextTick()解释https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/
  2. 墙裂推荐阮老师的博客 http://www.ruanyifeng.com/blog/2018/02/node-event-loop.html
    看完后,能否试图对上面的例子运行结果做出预判呢。
执行解释

首先,当前是本轮循环。在第一个阶段之前,已经有了line 37 process.nextTick回调注册,所以第一个打印是 process.nextTick 的第 1 次回调 。执行完后执行Promise.resolve,它是仅次于process.nextTick的优先级。在line 41 Promise.then里第一个执行的是instance.emit(‘jhs’),触发了事件回调,于是立刻执行line 9 的instance.on(‘jhs’注册的回调函数,打印 jhs事件回调调用 ,执行完毕后会回到line 43,又遇到 process.nextTick, 下面打印 promise的第 1 次回调。继续往下走会打印 promise的第 2 次回调。在line 48 执行完后,因为刚才又新加了一个process.nextTick,所以当前事件循环体里还有一个nextTick未执行,优先执行它,所以打印 process.nextTick 的第 2 次回调 。打印完后,当前事件循环体里没有了nextTick,也没有了promise等microtask。进入下轮循环,首先进入到times阶段。所以time阶段第一个执行的是line 14 这个0ms的定时器,打印 0 ms 后到期执行的定时器回调 ,这个执行完后,当前的100ms和200ms可能还没到期,就会进到下个阶段。发现poll阶段里面有两个回调函数还没执行,都是读文件操作,首先打印 第1次读取文件操作回调,然后 打印 第2次读取文件操作回调.等到这个poll队列被执行清空以后。进入ckeck阶段 发现又注册了setImmediate回调,打印 immediate 立即回调 。最后再次前往timer阶段,打印 100 ms 后到期执行的定时器回调和 200 ms 后到期执行的定时器回调。

然而,最后的运行结果如下:

process.nextTick 的第 1 次回调
jhs事件回调调用
promise的第 1 次回调
promise的第 2 次回调
process.nextTick 的第 2 次回调
0 ms 后到期执行的定时器回调
immediate 立即回调
第1次读取文件操作回调
第2次读取文件操作回调
100 ms 后到期执行的定时器回调
200 ms 后到期执行的定时器回调

发现,immediate立即回调在读文件操作之前执行,讲道理immediate在check阶段,而读文件操作在poll阶段,懵逼脸~~~我的理解,readFile是异步不阻塞的读文件,不影响event loop,莫非例子中两个文件读取较慢,所以进入了check阶段并执行了immediate,然后这两个读文件在下轮循环中执行。

还是应该深入到libuv源码

github 搜索 nodejs, 进入https://github.com/nodejs/node 项目后,英文输入法下按住t 键,搜索 deps/uv/src/unix/core.c,开始源码探索之旅吧~
目前我还只能看别人的分析,哭~~比如下面这篇分析的挺好。
3. https://cnodejs.org/topic/5a9108d78d6e16e56bb80882

以上…

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值