技术干货:process.nextTick揭秘

bbf28c3b0b07d544fd5dcf51fb15dc667d0a3a3e

本文作者:驻云科技,孙大庆

nodejs里有一个方法经常用到叫process.nextTick, 但是可能大部分人没有弄清楚这个方法的原理是什么,它到底比setTimeOut()到底快在哪里? 在nodejs的文档里,对这个方法的解释是: 
The process.nextTick() method adds the callback to the "next tick queue". Once the current turn of the event loop turn runs to completion, all callbacks currently in the next tick queue will be called. 

这段说明不难理解,但是有一个重要的概念没有说清楚,就是什么是next tick queue, 接下来我们试图说明这个问题。 我们知道nodejs处理回调底层使用的是libuv, libuv在处理事件回调的时候有三种方式,也就是uv_run启动event loop时的第二个参数,参照libuv的文档如下:

UV_RUN_DEFAULT:Runs the event loop until there are no more active and referenced handles orrequests. Returns non-zero if uv_stop() was called and there are still activehandles or requests. Returns zero in all other cases. UV_RUN_ONCE:Poll for i/o once. Note that this function blocks if there are no pendingcallbacks. Returns zero when done (no active handles or requests left), ornon-zero if more callbacks are expected (meaning you should run the event loopagain sometime in the future). UV_RUN_NOWAIT: Pollfor i/o once but don’t block if there are no pending callbacks. Returns zero ifdone (no active handles or requests left), or non-zero if more callbacks areexpected (meaning you should run the event loop again sometime in the future).

UV_RUN_DEFAULT: 这个值的功能是处理所有的事件回调,直到没有事件回调可以处理才返回, 否则一直阻塞。 

UV_RUN_ONCE: 顾名思义,这个值的功能是等待一次i/o事件的发生,并处理相关回到函数,然后返回,如果还有事件回调需要处理,则返回非零,否则返回零。
·UV_RUN_NOWAIT·:同样,字面意思是不等待i/o事件,有需要处理的事件就处理,否则立即返回,返回值和上面一致。 那么下面我们看看nodejs源码是怎么使用的,上源码:

9c5e697132bb99f2ec83fe3d98c5643db167dba8

StartNodeInstance 函数是nodejs启动一个node实例的函数,其中有如下循环:
be66f428ae7b0dc011059d8e6c1f864834a80d05
可以看到uv_run先后使用了UV_RUN_ONCE和UV_RUN_NOWAIT,这样的话,每一次事件触发,都会导致这个循环执行一次。 所以结论就是每一次这个循环的执行,算作一个tick, 那么queue是怎么来的, 看看node.js源码


18fae02ebcaf7cdf9d454c6c655c05a6d48f6e4f

...
nextTick的源码告诉我们,他只是将一个callback压入一个队列,等待下一个tick执行, 这就是传说中的next tick queue, 其之所以快,是应为setTimeout需要调用系统调用并等待操作系统内核触发计时器事件,而nextTick不用,下一次的tick自动执行。

本次的【技术干货】分享内容,是不是意犹未尽呢?那就快关注我们的微信公众号“架构云专家频道”吧,精彩内容,每日奉上!