今天讲一下nodejs的事件循环以下纯属我自己的理解,欢迎大家交流
以上是nodejs的事件循环流程,在这里面我们只需要关注timers poll check和nextTick Pormise部分不是说其他部分不重要而是,这个底层原理是c++的,不是node要关注的,在这里面:
timers队列
存放计时器的回调函数
poll轮询队列
除了timers、checks,绝大部分回调都会放入该队列,比如:文件的读取、监听用户请求等
如果poll中有回调,依次执行回调,直到清空队列。如果poll中没有回调,等待其他队列中出现回调,结束该阶段,进入下一阶段,如果其他队列也没有回调,持续等待,直到出现回调为止。但是还有一种情况是,如果一直没有回调而卡在poll队列中的话,在系统实在是受不了的情况下,在poll中的事件会出去check,timer中按流程转一圈,在回到poll中继续等,当然这个等待的时间每个电脑都不一样,看硬件的。
check检查队列
使用setImmediate的回调会直接进入这个队列
nextTick和Promise
事件循环中,每次打算执行一个回调之前,必须要先清空nextTick和promise队列
执行流程
计时器
在node中是按照顺序执行的也就是说每一个代码都是从timers到poll到check的,都是执行完每个模块内部的每个事件,才到下一个模块。
setTimeout( function f1(){
console.log("6666")
} , 5000)
我们执行这样的代码首先在node中同步代码直接执行,异步代码进入事件循环,f1函数先经过timer到poll停下,因为除了计时器、setImmediate,绝大部分回调都会放入该队列,并停下一直等到自己或外部的回调触发才结束该阶段。也就是说f1要在poll中待至少5s才触发回调将console.log(“6666”)返回timer(因为timer是存放计时器的回调函数),这里要注意了,在这里不是直接输出6666,而是poll模块先检查自己有没有代码要执行,处理完后再到check模块,再到下一个循环的timer执行输出6666,然后一直进行这个循环直到整个事件循环没有东西要执行了。
服务器
很多人可能不理解poll模块为什么非要有一个内部或者外部的回调触发它,因为这里一般放置的都是需要一直开启的东西比如服务器,
const http = require("http");
const server = http.createServer((req,res) => {
console.log("77777")
})
server.listen(3000)
这是一段开启服务器并且监听3000端口号的代码,这段代码一执行就会发生一直卡在poll模块里的情况,直到有用户访问3000端口才会是函数从poll来到check再到timer再到poll继续呆着,直到下一个访问请求。
nextTick和Promise
至于nextTick和Promise是什么,nextTick是超级vip,Promise是vip,什么意思呢在nodejs的事件循环中
大框代表事件队列,小框就代表事件回调,正常的流程是执行完timer中的3个事件后执行poll中的3个事件,但是在这之中每一个事件的执行完成之后都会看一下nextTick和Promise,如果nextTick中有东西就执行nextTick中的事件,nextTick执行完了之后就看一下Promise中有没有东西,有就执行Promise中的东西,于是执行流程就变成这样了
所以要注意了**每一个事件的执行完成之后都会看一下nextTick和Promise。**即使是nextTick和Promise内部的事件执行,也就是说如果在Promise中执行事件时,nextTick中添加了一个事件,即使Promise后面有事件在等待,也要回去执行nextTick新加的事件。在进入事件循环的时候第一时间看nextTick和Promise中有没有事件需要执行