前言:Node.js事件循环是家常便饭,但是在Node.js的执行过程中,事件循环并不是全部,在事件循环之外,处理microtasks的处理也是核心节点,比如nextTick和Promise任务的处理。本文介绍Node.js中微任务处理的相关内容。关于Promise、nextTick、setTimeout、setImmediate的执行顺序,网上的文章很多,面试题也很多。通过这篇文章,让你从原理上理解它们,解决相关问题而不拘泥于死记硬背和记录。1事件循环本文不打算详细讲解事件循环,因为相关的文章已经很多了,过程本身也不是很复杂。事件循环本质上是消费者和生产者的模型。我们可以理解为事件循环的每一阶段都维护一个任务队列,然后在每一轮事件循环中消费这些任务,也就是执行回调,然后在回调中就可以生产任务,从而驱动运行整个事件循环。当事件循环中没有生产者时,系统将退出。而有的producer会hold住eventloop,让整个系统都不会退出,比如我们启动了一个TCPserver。事件循环处理Node.js中的大部分执行流程,但不是全部。2微任务在Node.js中,典型的微任务包括nexiTick和Promise。官网说nextTick任务会在继续事件循环之前处理。描述比较宏观。我们来看看具体的实现细节。微任务的处理时序分为两个时间点。1.对象销毁时定义C++InternalCallbackScope对象。2.主动调用JS函数runNextTicks。2.1InternalCallbackScope我们先来看看InternalCallbackScope。通常在需要处理微任务的地方定义一个InternalCallbackScope对象,然后执行一些其他代码,最后退出作用域。{InternalCallbackScope//somecode}//退出作用域,析构我们来看看InternalCallbackScope析构函数的逻辑。InternalCallbackScope::~InternalCallbackScope(){Close();}voidInternalCallbackScope::Close(){tick_callback->Call(context,process,0,nullptr);}将在析构函数中执行tick_callback函数。让我们看看这个函数是什么。staticvoidSetTickCallback(constFunctionCallbackInfo&args){Environment*env=Environment::GetCurrent(args);CHECK(args[0]->IsFunction());env->set_tick_callback_function(args[0].As<函数>());}tick_callback由SetTickCallback设置。setTickCallback(processTicksAndRejections);我们可以看到setTickCallback设置的函数是processTicksAndRejections。functionprocessTicksAndRejections(){lettock;do{while(tock=queue.shift()){constcallback=tock.callback;callback();}runMicrotasks();}while(!queue.isEmpty()||processPromiseRejections());}processTicksAndRejections是处理微任务的函数,包括tick和Promise任务。现在我们已经看到了InternalCallbackScope对象的逻辑。那么我们来看看这个对象用在什么地方。第一个地方是Node.js初始化的时候,执行完用户JS之后,进入事件循环之前。看一下相关代码。我们看到在Node.js初始化的时候,执行完用户JS之后,会在进入事件循环之前处理一个microtask,所以如果我们在自己的初始化JS中调用nextTick,这个时候就会处理。第二个地方是每次从C、C++层执行JS层回调。MaybeLocalAsyncWrap::MakeCallback(constLocalcb,intargc,Local*argv){ProviderTypeprovider=provider_type();async_contextcontext{get_async_id(),get_trigger_async_id()};MaybeLocalret=InternalMakeCallback(env(),object(),object(),cb,argc,argv,context);returnret;}MakeCallback是C、C++层回调JS层的函数,在这个函数中调用了一个InternalMakeCallback。MaybeLocalInternalMakeCallback(Environment*env,Local