js的event loop机制,node eventloop

  js的event loop机制,node eventloop

  本文带你了解Node.js中的事件循环机制,希望对你有所帮助!

  node.js速度课程简介:进入学习

  今天,让我们学习nodeJs中的事件循环。对事件循环的理解一直是我的一大难点。希望本研究能够突破这一难点,通过这篇博客加深我对事件循环的理解和印象。

  

libuv

  在学习event-loop之前,先学习一下node的libuv。Libuv负责在不同的操作系统上实现不同的I/O模型,并将不同的实现抽象成可以应用于第三方应用的API。

  

问题

  在正式学习event-loop之前,想一个问题。

  setTimeout(()={

  console . log( time R1 );

  Promise.resolve()。然后(()={

  console . log( promise 1 );

  });

  }, 0);

  setTimeout(()={

  console . log( timer 2 );

  Promise.resolve()。然后(()={

  console . log( promise 2 );

  });

  }, 0);这段代码在浏览器中运行的结果是什么?

  在node中运行的结果是什么?

  在node8.6之前:

  node8.6之后:

  为什么会有这样的结果?我们以后再分析!

  

nodeJs 中的event-loop

  首先看一张图:

  在图中可以看到六个阶段,分别是:定时器、挂起回调、空闲/准备、轮询、检查和关闭回调。

  Timers阶段:主要实现setTimeOut,setInterval的回调。

  挂起回调阶段:执行某些系统调用时出错,比如网络通信的错误回调。

  空闲/准备阶段:仅在系统内使用(在此阶段我们无法控制干扰)

  轮询阶段:获取新的I/O事件,比如获取I/O回调以读取文件。在适合的情况下,nodejs将阻塞在这个阶段

  检查阶段:执行setImmediate的回调。

  例如,执行sokect的destory,close事件的回调

  每个阶段遵循FIFO(先入先出)的规则来执行任务队列中的任务。

  在这六个阶段中,我们重点关注timers,poll,check阶段。我们日常开发中的大多数异步任务都是在这三个阶段中处理的。

  

timers

  先说计时器阶段。timers是事件循环的第一个阶段,nodejs会去检查有没有已经过期了的timer,如果有,就将它的回调放入队列中。但是nodejs并不能保证timer在预设事件到了就会立即执行回调,这是因为nodejs对timer的过期检查不一定靠谱,它会受机器上其他运行程序的影响,或者是会遇到当前主线程不空闲的情况。

  对于这里的不确定性,官网举了一个例子:

  首先声明一个setTimeOut,然后从外部读取一个文件。当文件读取操作超过定时器时间时,文件读取操作会延迟定时器的回调。这是主线程没有空闲的情况。

  

poll

  轮询阶段主要执行两件事:

  1.在轮询阶段处理任务队列。

  2.当超时的定时器执行其回调函数时。

  在上图中,我们还可以看到:在poll阶段执行完poll任务队列的任务之后,会去检查有无预设的setImmediate,如果有,则进入check阶段,如果没有,则nodejs将会阻塞在这里。

  这里我们会有一个问题。如果堵车是在轮询阶段,我们设置的定时器不会执行失败吗?

  其实当event-loop阻塞在poll阶段时,nodejs会有一个检查机制,它会去检查timers队列是否为空,如果不为空,则重新进入timers阶段。

  

check

  检查检查阶段主要执行setImmediate的回调函数。

  

小总结

  event-loop的每个阶段都有一个队列,当event-loop达到某个阶段之后,将执行这个阶段的任务队列,直到队列清空或者达到系统规定的最大回调限制之后,才会进入下一个阶段。当所有阶段都执行完成一次之后,称event-loop完成一个tick。

  

案例

  以上,我们已经完成了event-loop的理论部分,但是仅仅靠理论还是无法清晰的理解event-loop。让我们通过几个演示对事件循环有更深的理解!

  demo1

  const fs=require(fs )

  fs.readFile(test.txt ,()={

  console.log(readFile )

  setTimeout(()={

  console . log( settime out );

  },0)

  setImmediate(()={

  console.log(setImmediate )

  })

  })执行结果:

  可见执行结果与我们之前的分析是一致的!

  demo2

  const fs=require( fs );

  const event emitter=require( events )。EventEmitter

  设pos=0;

  const messenger=new event emitter();

  messenger.on(message ,function (msg) {

  console . log(pos message: msg );//

  });

  console . log(pos first );//

  process.nextTick(function () {

  console . log(pos next tick );//

  });

  messenger.emit(message , hello!);

  fs.stat(__filename,function () {

  console . log(pos stat );//

  });

  setTimeout(function () {

  console.log( pos 快速计时器);//

  }, 0);

  setTimeout(function () {

  console.log( pos 长计时器);//

  }, 30);

  setImmediate(function () {

  console . log(pos immediate );//

  });

  console . log(pos last );//结果:

  

了解下浏览器和node的event-loop差异在什么地方

  在node 8.6 之前:

  浏览器中的微任务队列会在每个宏任务完成后执行,而节点中的微任务会在事件周期的各阶段之间执行,即微任务队列会在每个阶段完成后执行。

  在8.6之后:

  与浏览器节点中微任务的执行一致!

  于是,在文章的开头,我们提出的思考问题就有了结果。

  

关于 process.nextTick()和setImmediate

  

process.nextTick()

  语法:process.nextTick(回调,agrs)

  执行时间:

  这个函数其实是独立于 Event Loop 之外的,它有一个自己的队列,当每个阶段完成后,如果存在 nextTick 队列,就会清空队列中的所有回调函数,并且优先于其他 microtask 执行。递归的调用process.nextTick()会导致I/O starving,官方推荐使用setImmediate()

  饥饿现象的解释:

  const fs=require( fs );

  fs.readFile(test.txt ,(err,msg)={

  console . log( readFile );

  });

  设索引=0;

  函数处理程序(){

  if (index=30)返回;

  指数;

  console.log(nextTick 索引);

  process.nextTick(处理程序);

  }

  handler();运行结果:

  可以看到,读取文件的回调直到nextTick函数执行30次才会执行!这种现象被称为I/O 饥饿

  当我们将process.nextTick改为setImmediate时

  const fs=require( fs );

  fs.readFile(test.txt ,(err,msg)={

  console . log( readFile );

  });

  设索引=0;

  函数处理程序(){

  if (index=30)返回;

  指数;

  console.log(nextTick 索引);

  setImmediate(处理程序);

  }

  handler();结果:

  这两个区别的原因是嵌套调用setImmediate的回调被放在下一个事件循环中!

  

event-loop核心思维导图

  

结束语

  通过今天的学习,我对事件循环有了更深的理解。那么,下次见。好好学习,天天向上!

  有关编程的更多信息,请访问:编程视频!也就是说,上面的文章谈到了Node.js中事件循环机制的细节请关注我们的其他相关文章了解更多!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: