当前位置: 首页 > 后端技术 > Node.js

阅读《Node.js 事件循环,定时器和 process.nextTick()》

时间:2023-04-03 14:46:31 Node.js

,以下均无效。有大神写了一篇通俗易懂的文章:英文原文:https://blog.insiderattack.ne...翻译:https://zhuanlan.zhihu.com/p/...官方文档的Node.jsEventLoop,Timers,andprocess.nextTick()[中文版]Node.js事件循环,定时器和process.nextTick(),详见文档,这里摘录一两个重点。┌────────────────────────────┐┌──>│计时器││└──────────────┬──────────────┘│┌────────────┴──────────────┐││等待回调││└──────────────┬────────────┘│┌────────────┴──────────────┐││空闲,准备││└──────────────┬──────────────┘┌────────────────┐│┌────────────┴──────────────┐│传入:│││投票│<──────┤连接,││└──────────────┬──────────────┘│数据等││┌─────────────┴──────────────┐└────────────────┘││检查││└──────────────┬────────────┘│┌────────────┴──────────────┐└──┤关闭回调│└────────────────────────────┘process.nextTick()process。过渡,在在处理一些需要的的执行执行。。使用使用不不不不不使用使用使用使用使用使用会会造成造成造成一些一些问题。递归递归调用调用调用调用调用调用地process.nexttick()nexttick()将将将将会会会导致导致事件process.nextTick()调用。这也说明process.nextTick()中的递归调用会在本次nextTick执行的过程中立即排队执行,而不是等到下一个事件阶段执行完后再执行nextTick。深入阅读githubissue-non-deterministicorderofexecutionofsetTimeoutvssetImmediateIssue1官方文档介绍setImmediate()vssetTimeout()时说如果运行以下不在I/O周期的脚本(即主模块),然后执行这两个计时器的顺序是不确定的,因为如果我们运行以下不在I/O周期内的脚本(即主模块),它受进程性能的约束,这两个定时器的执行顺序是不确定的,因为它受制于进程的性能这里“受制于进程的性能”具体是什么意思?详见:https://github.com/nodejs/hel...摘录:Node中的事件由uv_run()驱动,部分源码如下:intuv_run(uv_loop_t*loop,uv_run_modemode){内部超时;诠释;intran_pending;r=uv__loop_alive(loop);如果(!r)uv__update_time(循环);while(r!=0&&loop->stop_flag==0){uv__update_time(loop);uv__run_timers(循环);ran_pending=uv__run_pending(循环);uv__run_idle(循环);uv__run_prepare(循环);......uv__io_poll(loop,timeout);uv__run_check(循环);uv__run_closing_handles(循环);根据文档,while循环中的处理对应于在事件循环的每个阶段,但在开始uv__run_timers(loop)定时器阶段处理之前,都会调用这样一段代码uv__update_time(loop)。而这个函数定义如下:voiduv_update_time(uv_loop_t*loop){uv__update_time(loop);}uv__update_time定义如下,它调用了一个函数uv__hrtime。UV_UNUSED(staticvoiduv__update_time(uv_loop_t*loop)){/*如果可用,使用快速时间源。我们只需要毫秒精度。*/loop->time=uv__hrtime(UV_CLOCK_FAST)/1000000;}uv__hrtime的调用依赖于系统,这是一个CPU耗时的工作,系统需要再次调用clock_gettime。所以这个函数调用的耗时会受到此时机器上运行的其他程序的影响。当代码执行到timer阶段,如果此时已有定时器达到阈值,则将其取出执行,所以setImmediatesetTimeout的回调执行顺序取决于当时进程的表现。另:即使setTimeout设置等待时间为0,其最小等待时间也会转换为1ms。问题2consttimer=()=>{setTimeout(timer,1)setImmediate(()=>console.log('immediatefired'))//永远不会记录constdate=newDate()while(newDate()-date<2){}}timer()在老版本Node中嵌套调用setImmediate会导致事件循环一直卡在check阶段,即上述过程中提到的“饿死”问题.nextTick()将会发生。将Node版本切换到6.9.1发现确实有问题,后来切换到8.9.4等更新的版本就没有这个问题了。