Node之Event loop

Posted 架构师日刊

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Node之Event loop相关的知识,希望对你有一定的参考价值。


阅读本文约需要5分钟



1、长期为你提供最优质的学习资源!

2、给你解决技术问题!

4、每周1、3、5送纸质书籍免费送给大家,每年至少送书800本书!

5、为大家推荐靠谱的就业单位!

请注意!我上面说的5点全部都是免费的!全网你应该找不到第二家吧!

当然,大家在我私人微信上问我问题,仅限回答web前端、java相关的。

---------------------------

好了,接下来开始今天的技术分享!上次老师跟大家分享了Node之简介的知识,今天跟大家分享下Node之Event loop的知识。 

1 Event loop是什么?

Event loop 允许node.js执行非阻塞I/O操作(尽管JS是单线程的),也就是在相应情况下,尽可能的将任务交给系统内核。

多数内核是多线程的,可以同时处理多个任务。当其中一个任务完成时,相应的callback被插入到轮询队列中,最终被执行。

2 事件循环

事件循环包含几个阶段,相应的阶段做相应的事。

初始化: Node.js启动后,会进行一些初始化 


初始化Event loop处理目标脚本然后进入事件循环


Node之Event loop

每个阶段,都有其FIFO队列,用来执行回调函数。 

每个阶段都是特殊的。当进行到该阶段时,会执行该阶段特有的操作,然后执行该阶段队列中的回调。当队列空,或者达到执行次数限制,事件循环进行下阶段。循环往复。
3 阶段总览


timers:执行setTimeout()和setInterval安排的回调I/O callbacks: 执行几乎所有异常的close回调,由timer和setImmediate执行的回调。idle,prepare: 只用于内部poll : 获取新的I/O事件,node在该阶段会适当的阻塞check : setImmediate的回调被调用close callbacks: e.g socket.on(‘close’,…);在每次运行事件循环之间,node.j检查是否有正在等待的异步i/o调用、timers等。如果没有,就清除并结束(退出程序),例如:执行一个程序,仅有一句话(var a= ‘hello’;),处理完目标代码后,不会进入evetloop,而是直接结束程序。


每个阶段

Timers:定时器可以设置回调函数在指定时间后运行。这个回调函数会在能够被调度后,尽可能快的运行。操作系统的调度,或其他回调数的运行,可能会延迟该回调函数的运行。**通常,poll阶段控制定时器的运行。

当事件循环进入poll阶段,根据该阶段队列内容执行: 


执行队列中的回调函数当队列中没有回调函数时,且定时器设置时间已过回到timers 阶段,执行相应的回调函数**为了防止poll阶段过长,libuv根据为不同系统设置了poll阶段的最长事件。


I/O callbacks:该阶段执行一些如TCP错误之类的系统操作的会ID回调。

Poll(轮询):

两个主要功能


执行定时器设置并到期的回调函数,然后处理poll队列中的事件

工作机制:当没有timers被调度,分两种情况


如果poll队列不为空,会挨个执行队列里的callback,直到队列为空,或达到系统限制如果poll队列为空,分两种情况:1,如果执行了setImmediate(),eventloop会结束poll阶段,进入到check阶段执行 ,2,如果没有执行setImmediate(),eventloop会等待callback进入队列



一旦poll队列为空,evetloop会检查timers,如果计时已到,event loop 会回到 timers 阶段,执行相应的回调函数.

check阶段

poll阶段变为空闲、等待状态时,一旦调用setImmediate(),eventloop会进入check 阶段,而不是在poll阶段等待。

close callbacks阶段

例如:socket或句柄关闭,close事件会触发这个阶段。或者通过process.nextTick()触发

4 总结

Node.js事件循环有实际上7、8个阶段,但我们关注-node实际使用的,就是前面说的几个。每个阶段都有自己的队列。本阶段执行完成后,执行下一个阶段。循环顺序不是完全固定的,很多阶段都是由外部事件触发的。

重要的三阶段:

timers,定时器阶段: 

执行定时任务(setTimeOut(), setInterval())

poll 轮询阶段:


处理到期的定时器任务,然后(因为最开始阶段队列为空,一旦队列为空,就会检查是否有到期的定时器任务)处理队列任务,直到队列空,或达到上限如果队列为空:如果setImmediate,终止轮询阶段,进入检查阶段执行。如果没setImmediate,查看有没有定时器任务到期,有的话就到timers阶段,执行回调函数.


check 检查阶段

轮询阶段空闲,且有setImmediate的时候,进入检查阶段

不重要二阶段

I/O callbacks阶段:处理I/O异常错误

close callbacks阶段: 处理各种close事件回调

5 代码
关于poll阶段和timers阶段调用先后


const fs = require('fs');
setTimeout(function(){ console.log('ff');},0);
function func(cb) { fs.readFile('xxx.js',cb);}
func( () => { console.log('a');})
参考:https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/#why-would-that-be-allowed

今天就分享这么多,关于Node之 Event loop,你学会了多少欢迎在留言区评论,对于有价值的留言,我们都会一一回复的。如果觉得文章对你有一丢丢帮助,请点右下角【在看】,让更多人看到该文章。




Node之Event loop

全网应该只有我能做到了吧!有技术问题可以在微信上问我!(如下图)


以上是关于Node之Event loop的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript之彻底学会Event Loop

[未解决问题记录]python asyncio+aiohttp出现Exception ignored:RuntimeError('Event loop is closed')(代码片段

高级前端养成39js专精07之Event Loop

理解 Node.js 的 Event loop

一篇文章教会你 Event loop——浏览器和 Node

定时器setTimeout()和Node.js的Event Loop