nodejs-第二章-第二节-nodejs事件循环(2-1)

当Node.js启动时会初始化event loop,每个event loop 都会包含按如下六个节点循环,nodejs事件循环和浏览器事件循环完全不一样。

nodejs事件循环

  • 图中的每个方框被称作事件循环的一个"阶段",这6个阶段为一轮事件循环;
阶段概览
  • timers(定时器): 此阶段执行那些有setTimeout() 和 setInterval()调度的回调函数;
  • I/O callbacks(I/O回调):此阶段会执行几乎所有的回调函数,除了close callbacks(关闭回调) 和 那些有timers与setImmediate()调度的回调;
  • idle(空转),prepare: 此阶段只在内部使用;
  • poll(轮询): 检索新的I/O事件;在恰当的时候Node会阻塞在这个节点;
  • check(检查): setImmediate() 设置的回调会在此阶段被调用;
  • close callbacks(关闭事件的回调):
    • 如:socket.on('close',...);此类的回调会在此阶段被调用; 在事件循环每次运行之间,Node.js会检查它是否等待异步I/O或定时器,如果没有的话就会自动关闭;

如果event loop 进入了poll阶段,且代码未设定timer,将会发生下面的情况:

  • 如果poll queue不为空,event loop将同步的执行queue里的callback,知道queue为空,或执行的callback达到系统的上限;
  • 如果poll queue为空,将会发生下面的情况:
    • 如果代码已经被setImmediate()设定了callback,event loop 将结束poll阶段进入check阶段,并执行check阶段的queue(check阶段的queue是setImmediate设定的)
    • 如果代码没有设定setImmediate(callback),event loop将阻塞在该阶段等待callbacks加入poll queue,一旦达到就立即执行;

如果event loop进入了poll阶段,且代码设定了timer:

  • 如果poll queue进入空状态时(即poll阶段为空闲状态),event loop将阻塞在该阶段等待callbacks加入poll queue,一旦达到就立即执行;

setImmediate约定于setTimeout(cb,0)
  • path.resolve() 方法会把一个路径或路径片段的序列解析为一个绝对路径。

  • __dirname 总是指向当前文件夹的绝对路径

  • __filename 总是指向当前文件的绝对路径

  • note:

    • io: 浏览器线程去调用一些异步的回调
  • 执行代码1
var fs = require('fs');
var path = require('path');
function someAsyncOperation(callback) {
  // 花费2ms
  fs.readFileSync('./read.txt', callback);
}
var timeoutScheduled = Date.now();
var fileReadTime = 0;
setTimeout(function() {
  var delay = Date.now() - timeoutScheduled;
  console.log(`setTimeout ${delay} ms have passed since I was sheculed`);
  console.log('fileReaderTime', fileReadTime - timeoutScheduled);
}, 10);

someAsyncOperation(function() {
  fileReadtime = Date.now();
  while (Date.now() - fileReadTime < 20) {}
});
  • 执行过程:
    • setTimeout和readFile先后加入io
    • setTimeout执行进入io;(需要10ms)
    • readfile执行,也进入io;(需要2ms)
    • 2ms之后, redfile已经读取完毕,加入poll队列,此时poll为空,执行someAsyncOperation回调;
    • 由于此回调有while,这里阻塞20ms;执行完为22ms
    • 在10ms时,setTimeout不能执行,因为js是单线程,setTimeout一直被阻塞
    • 执行完之后(22ms以后),poll 进入空闲状态
    • event loop检查timer,setTimeout回调;
  • 执行结果:
    • readFile执行22ms
    • setTimeout执行22ms之后
  • 执行代码2
var fs = require('fs');
var path = require('path');
function someAsyncOperation(callback) {
  // 花费9ms
  fs.readFileSync('./read.txt', callback);
}
var timeoutScheduled = Date.now();
var fileReadTime = 0;
setTimeout(function() {
  var delay = Date.now() - timeoutScheduled;
  console.log(`setTimeout ${delay} ms have passed since I was sheculed`);
  console.log('fileReaderTime', fileReadTime - timeoutScheduled);
}, 5);

someAsyncOperation(function() {
  fileReadtime = Date.now();
  while (Date.now() - fileReadTime < 20) {}
});
  • 执行结果
    • setTimeout执行:5ms
    • readFile执行9 ~ 29ms
  • 执行代码3
  • 在nodejs中,setTimeout(fn,0) === setTimeout(fn,0)
  • 在浏览器中,setTimeout(fn,0) === setTimeout(fn,4)
setImmediate(() =>{
    console.log('setImmediate')
},0)

setTimeout(() =>{
    console.log('setTimeout')
},0)

// setTimeout 和 setImmediate的执行顺序不确定
// 因为event loop的启动也是需要时间的,可能执行到poll阶段时已经超过了1ms,此时setTimeout会先执行
const fs = require('fs');
const path = require('path');
fs.readFile(path.resolve(__dirname, '/read.txt'), () => {
  setTimeout(() => {
    console.log('setTimeout');
  }, 0);
  setImmediate(() => {
    console.log('setImmediate');
  }, 0);
});
// 执行顺序是确定的, setImmediate,setTimeout
  • 执行过程:
    • 执行fs,第一轮主线程没有timer和setImmediate
    • 假设readFile需要2ms,执行回调
    • 由poll进入check,setImmediate会先调用
    • 在第二轮的timer阶段,会执行setTimeout

转载于:https://my.oschina.net/u/3150996/blog/3083209

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值