Jobs

在ES6中,在事件轮询队列之上引入了一层新概念,称为“工作队列(Job queue)”。你最有可能接触它的地方是在Promises(见第三章)的异步行为中。

不幸的是,它目前是一个没有公开API的机制,因此要演示它有些兜圈子。我们不得不仅仅在概念上描述它,这样当我们在第三章中讨论异步行为时,你将会理解那些动作行为是如何排程与处理的。

那么,我能找到的考虑它的最佳方式是:“工作队列”是一个挂靠在事件轮询队列的每个tick末尾的队列。在事件轮询的一个tick期间内,某些可能发生的隐含异步动作的行为将不会导致一个全新的事件加入事件轮询队列,而是在当前tick的工作队列的末尾加入一个新的记录(也就是一个Job)。

它好像是在说,“哦,另一件需要我 稍后 去做的事儿,但是保证它在其他任何事情发生之间发生。”

或者,用一个比喻:事件轮询队列就像一个游乐园项目,一旦你乘坐完一次,你就不得不去队尾排队来乘坐下一次。而工作队列就像乘坐完后,立即插队乘坐下一次。

一个Job还可能会导致更多的Job被加入同一个队列的末尾。所以,一个在理论上可能的情况是,Job“轮询”(一个Job持续不断地加入其他Job等)会无限地转下去,从而拖住程序不能移动到一下一个事件轮询tick。这与在你的代码中表达一个长时间运行或无限循环(比如while (true) ..)在概念上几乎是一样的。

Job的精神有点儿像setTimeout(..0)黑科技,但以一种定义明确得多的方式实现,而且保证顺序: 稍后,但尽快

让我们想象一个用于Job排程的API,并叫它schedule(..)。考虑如下代码:

  1. console.log( "A" );
  2. setTimeout( function(){
  3. console.log( "B" );
  4. }, 0 );
  5. // 理论上的 "Job API"
  6. schedule( function(){
  7. console.log( "C" );
  8. schedule( function(){
  9. console.log( "D" );
  10. } );
  11. } );

你肯能会期望它打印出A B C D,但是它将会打出A C D B,因为Job发生在当前的事件轮询tick的末尾,而定时器会在 下一个 事件轮询tick(如果可用的话!)触发排程。

在第三章中,我们会看到Promises的异步行为是基于Job的,所以搞明白它与事件轮询行为的联系是很重要的。