node源码粗读(9):nextTick、timers API、MicroTasks注册到执行全阶段解读
发布于 5 个月前 作者 xtx1130 597 次浏览 来自 分享

本文主要介绍nextTick、timers API、MicroTasks几类任务是在什么时候注册和执行的,也会从node 的bootstrap到evnet-loop过程做一个简单的介绍

整体流程

在这里以下面这段代码为例子,画一下整体的运行流程:

setTimeout(() => console.log('timers API'), 10)
new Promise((resolve, reject) => resolve('microtask run')).then(arg => console.log(arg))
process.nextTick(() => console.log('run next tick'))
setImmediate(() => console.log('setImmediate API'))

issue20-1 注意:

Environment::Start

在这里不做过多详细介绍了,之前的文章中介绍过很多。有一个知识点需要注意就是:Immediate是在这个阶段注册到uv_check_start中的。此Immediate其实是Environment::CheckImmediate函数,保证之后event-loop在运行的时候能在check阶段运行这个函数,进而触发immediate_callback_function实现对ImmediateList的调用。
至于idle部分,是为了在有ImmediateList的时候直接跳过poll阶段,毕竟poll是阻塞运行的。

bootstrap阶段

bootstrap阶段是node运行时候的构建阶段,也是最基础的阶段。bootstrap阶段会把整体的node架子搭起来(在这里不做详细介绍),之后运行业务代码。比如本文中的这个例子,上图中画的应该也比较清晰了,顺序执行。唯一的区别是:在执行不同API的时候,callback的去向是不一致的。从上图中也能看出来,这几个API最终的去向分别是:TimersList、microTask、immediateQueue、nextTickQueue。
其中,setTimeout在注册的时候会创建TimerWrap的实例,在创建实例的时候会初始化uv_timer,之后再通过TimerWrap.start启动uv_timer_start,开始监听,到时间触发运行回调函数: issue20-2 nextTick在注册之后且bootstrap构建结束后运行SetupNextTick函数,从而触发nextTick的运行,而nextTick在运行之后会触发runMicroTasks(),清空bootstrap阶段的microTask: issue20-3

event-loop阶段

在bootstrap之后便进入了event-loop。event-loop第一个阶段便是timers,在这里如果有到时间的Timer,便会触发OnTimeoutOnTimeout会触发InternalMakeCallback从而执行TimersList中的函数。而在执行完后还会触发InternalCallbackScope::Close,在这个函数中会触发nextTick,在触发nextTick后触发microTasks。setTimeout简易流程如下: issue20-4 也正是InternalMakeCallbackInternalCallbackScope::Close使得libuv和v8紧紧的联系在了一起,一方面可以通过setTimeout来设置运行时间;另一方面又可以在setTimeout的回调中书写js代码。

原文地址:https://github.com/xtx1130/blog/issues/20,欢迎star和fork,如果有错误之处,还请在回复或者issue下面斧正。

by 小菜

回到顶部