set 有序吗js_js中promise,setTimeout 中顺序

本文详细讲解了Node.js和Chrome V8引擎在异步事件处理中的共同点,区分了IO异步和非IO异步,探讨了process.nextTick、promise等microTask与setTimeout等macroTask的区别,以及事件循环(event loop)如何管理网络IO和microTask的执行顺序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

node和chrome js执行引擎都是以V8为核心的。因此,在异步事件处理上十分相似。

在node中,异步分为两种,一种是IO的异步,一种是非IO的异步。

异步IO有磁盘IO和网络IO,非IO异步有process.nextTick, promise, setTimeout, setImmediate.。

非异步IO中,process.nextTick, promise等属于microTask, setTimeout, setImmediate 是macroTask。

异步IO的调用需要底层libuv层支持,较为复杂,属于macroTask。

比如,在js中发起一个网络请求时,js代码调用node核心模块,核心模块再调用C++内建模块。内建模块通过libuv进行系统调用。系统调用的过程中,创建相应的请求对象,从js层传入的参数和当前方法都被封装在请求对象中,回调函数被设置在请求对象的oncomplete_sym上,对象包装完毕后,调用QueueUserWorkItem将请求对象推入线程池中等待执行。

js层继续执行后续执行栈中的代码。

在内核层,当线程池中有空闲线程时,调用相应底层函数,发起网络请求。

在v8是单线程的,但是浏览器和操作系统是多线程的(!important)。(意味深长~~)

此时,JavaScript调用立即返回。根据当前的执行栈,继续执行原执行栈的函数。检查microTask中是否任务可以执行,若有,则按照优先级、调用先后顺序依次执行,直到将microTask执行结束。

网络请求对象送入IO线程池等待执行,内核利用端口发起真正的网络请求,并侦听网络端口,一旦接收到网络请求,表示内核层面的网络请求执行完毕。

执行完毕后,会将结果储存在请求对象的result属性上。window下调用PostQueuedCompletionStatus通知IOCP,告知当前对象操作已经完成,并将线程归还线程池。

内核发送IO观察者形成事件,每次Tick时,调用GetQueuedCompletionStatus获取执行状态,得到执行完的IO操作,将请求对象加入IO观察者队列中,将其当作事件处理。

网络IO属于macroTask,这个macroTask放入event loop中。event loop中的异步IO都有相应的观察者,每次tick,检查优先级较高的观察者。

process.nextTick 属于idle观察者,setImmediate是check观察者。idle观察者优于IO观察者,IO观察者优于check观察者。

如有IO观察者回调函数,取出请求对象的result作为参数,在js层回调执行,结束调用。

然后检查microTask,执行所有microTask函数。同时,microTask在event loop中也有优先级。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值