您的位置:首页 > Web前端 > Node.js

nodejs事件循环学习

2019-02-27 00:08 183 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/Try_yang/article/details/87958279

nodejs的事件循环

前言

这是笔者的第一篇博客,写博客的目的也仅仅是对自己所学习的知识做一个总结,如有理解不正确的地方还请各路大神指出,希望在编程的道路上越走越远。

node中的事件循环的几个阶段

1.Timers阶段

此阶段主要用于处理定时器相关的回调函数

2.I/O callbacks

除了定时器,close事件以外的其他事件的回调函数

3.idle,prepare(不常用,未做研究)

4.Poll

轮询阶段,用来检查有没有新的事件出现,这些事件的回调方法可能出于其他几个事件循环阶段,这里可能发生阻塞
poll阶段的判断规则:
1.如果进入到poll阶段的时候有已经到期的定时器,那么直接执行定时器回调,比如说将定时器时间设置为0,将会直接执行
2.处理poll阶段对应的事件队列的事件
如果此时poll阶段的事件队列不是空,那么则按照先进先出的顺序执行事件
如果是空,判断是否进入check,是的话执行check阶段回调,没有进入check,那么poll阶段继续轮询,同时检查是否有定时器完成,有就直接进入到timers阶段,执行对应回调函数

5.Check

为setImmediate存在的一个循环阶段,当事件循环进入到poll后,就会检查代码是否调用了setImmediate,如果调用,则立刻跳出poll进入check阶段,执行回调,执行完毕后开始下一轮事件循环

6.close callback

如果产生一个close事件,该事件会被加入到对应的队列,close阶段执行完毕,本轮事件循环结束,进入下一轮循环

7.伪代码说明

// 事件循环本身相当于一个死循环,当代码开始执行的时候,事件循环就已经启动了
// 然后顺序调用不同阶段的方法
while(true){
// timer阶段
timer()
// I/O callbacks阶段
IO()
// idle阶段
IDLE()
// poll阶段
poll()
// check阶段
check()
// close阶段
close()
}
// 在一次循环中,当事件循环进入到某一阶段,加入进入到check阶段,突然timer阶段的事件就绪,也会等到当前这次循环结束,再去执行对应的timer阶段的回调函数
// 下面看这里例子
const fs = require('fs')

// timers阶段
const startTime = Date.now();
setTimeout(() => {
const endTime = Date.now()
console.log(`timers: ${endTime - startTime}`)
}, 1000)

// poll阶段(等待新的事件出现)
const readFileStart =  Date.now();
fs.readFile('./Demo.txt', (err, data) => {
if (err) throw err
let endTime = Date.now()
// 获取文件读取的时间
console.log(`read time: ${endTime - readFileStart}`)
// 通过while循环将fs回调强制阻塞5000s
while(endTime - readFileStart < 5000){
endTime = Date.now()
}

})

// check阶段
setImmediate(() => {
console.log('check阶段')
})
/*控制台打印
check阶段
read time: 9
timers: 5008
通过上述结果进行分析,
1.代码执行到定时器setTimeOut,目前timers阶段对应的事件列表为空,在1000s后才会放入事件
2.事件循环进入到poll阶段,开始不断的轮询监听事件
3.fs模块异步执行,根据文件大小,可能执行时间长短不同,这里我使用的小文件,事件大概在9s左右
4.setImmediate执行,poll阶段暂时未监测到事件,发现有setImmediate函数,跳转到check阶段执行check阶段事件(打印check阶段),第一次时间循环结束,开始下一轮事件循环
5.因为时间仍未到定时器截止时间,所以事件循环有一次进入到poll阶段,进行轮询
6.读取文件完毕,fs产生了一个事件进入到poll阶段的事件队列,此时事件队列准备执行callback,所以会打印(read time: 9),人工阻塞了5s,虽然此时timer定时器事件已经被添加,但是因为这一阶段的事件循环为完成,所以不会被执行,(如果这里是死循环,那么定时器代码永远无法执行)
7.fs回调阻塞5s后,当前事件循环结束,进入到下一轮事件循环,发现timer事件队列有事件,所以开始执行 打印timers: 5008

ps:
1.将定时器延迟时间改为5ms的时候,小于文件读取时间,那么就会先监听到timers阶段有事件进入,从而进入到timers阶段执行,执行完毕继续进行事件循环
check阶段
timers: 6
read time: 5008
2.将定时器事件设置为0ms,会在进入到poll阶段的时候发现timers阶段已经有callback,那么会直接执行,然后执行完毕在下一阶段循环,执行check阶段,poll队列的回调函数
timers: 2
check阶段
read time: 7
*/

node是单线程运行,所以每个时间只能处理一个事件,所以在事件循环中,本质上还是不同阶段的回调方法的同步调用,当一次循环结束后,再开始下一轮循环,已上是笔者对事件循环的理解,如果有理解不到位的地方,请各路大神指正

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: