欢迎光临散文网 会员登陆 & 注册

nodeJs事件循环

2023-04-13 21:06 作者:TongMarsh  | 我要投稿
  1. Nodejs运行时

JS语言是同步,阻塞,单线程的,但是nodejs不是。Nodejs由三个主要组件:

  • 外部依赖例如 v8,libuv,crypto

  • 提供文件和网络服务的c++模块

  • 基于c++模块上层封装的JS库


nodejs的异步特性主要由libuv提供。libuv是跨平台的使用c语言写的库,它主要提供对异步操作的支持。

2. 代码运行过程

当我们在Nodejs中执行JS代码时,是由v8引擎处理代码执行,v8包括一块内存区域(堆)和调用栈。当定义函数,变量时,从堆中分配内存,当执行代码时将函数入栈,函数返回时出栈。

当执行异步操作时,libuv将接管该任务,然后使用操作系统的异步机制运行任务。如果缺乏系统级的异步机制,就使用线程池运行任务,保证主线程不被阻塞。

3. Event Loop

事件循环是一个nodejs应用运行后一直存在的循环。存在着六个不同的队列,每个都存储着不同的回调。

  • Timer queue(定时器队列),最小堆,由setTimeout, setInterval创建

  • IO队列:文件、网络操作

  • check队列,任务由setImmediate产生,node专有

  • close队列, 与异步任务的close事件相关

  • nextTick队列

  • promise队列

除了两个微任务队列,其他队列都是libuv自带的


如何工作?

同步代码优于异步代码,事件循环是call stack为空后开始。事件循环遵循的优先级规则:

  • 微任务队列有任务,先处理完。nextTick先于promise

  • 定时器任务执行

  • IO队列

  • check队列

  • close队列

需要注意的是在定时器队列,IO队列,check队列,close队列执行一个任务后都会检查并运行微任务队列。

4. 实验

实验1


输出


结论:同步先于异步


实验2


输出


结论:nextTick先于promise


实验3


输出


解析:

nextTick内部增加的nextTick任务还是先于promise,因为nexttick队列清完后才会执行promise队列的任务。

promise里增加的nextTick任务晚于其他的promise,因为此时是在执行promise阶段,需要清空promise才会检查nextTick队列。


实验4



输出


结论:nextTick先于promise;微任务先于setTimeout;每个Timer任务后会检查执行微任务。


实验6


输出


结论:Timer队列是按时间排序的


实验7



输出


结论:微任务先于io任务


实验8


输出:不确定

解析:setTimeout 0通常内部会取1ms,也就是1ms后执行Timer任务,而cpu进入事件循环的时机不定,所以有可能进入事件循环时已经过了1ms,那么先执行timer任务,也可能进入时定时任务没到时间,会先执行IO任务。


实验9


输出


解析:

代码最后加了循环保证进入事件循环时定时器任务已经到期,所以先执行Timer任务


实验10


输出

1

解析:按理说IO任务先于check任务,但是第一次事件循环时IO任务的callback并不在队列里。在两个队列之间会通过IO polling的方式去查看io任务是否完成,完成了就将callback加到队列里,然后下一轮循环时会调用

I/O events are polled and callback functions are added to the I/O queue only after the I/O is complete



参考:https://www.builder.io/blog/visualizing-nodejs-io-queue



nodeJs事件循环的评论 (共 条)

分享到微博请遵守国家法律