事件循环上下文中的微任务和macros任务之间的区别

我刚读完Promises / A +规范,偶然发现了microtask和macrotask这两个术语:参见http://promisesaplus.com/#notes

我从来没有听说过这些条款,现在我很好奇它们有什么不同?

我已经试图在网上find一些信息,但是我发现的这个post是从w3.org档案(这不能解释我的不同之处): http : //lists.w3.org/Archives /Public/public-nextweb/2013Jul/0018.html

另外,我发现了一个名为“macrotask”的npm模块: https : //www.npmjs.org/package/macrotask再一次,没有澄清究竟是什么区别。

我所知道的是,它与事件循环有关,如https://html.spec.whatwg.org/multipage/webappapis.html#task-queue和https://html.spec.whatwg中所述.ORG /多页/ webappapis.html#执行-A-microtask检查点

根据WHATWG规范,我知道理论上我应该能够自己提取差异。 但我相信其他人也可以从专家的简短解释中获益。

    一个事件循环的复原只有一个任务正在从macrotask队列中处理 (这个队列在WHATWG规范中简单地称为任务队列 )。 在这个macros任务结束之后,所有可用的微任务将被处理,即在相同的复飞周期内。 在处理这些微任务时,他们可以排队更多的微任务,这些微任务都将被逐个运行,直到微任务队列耗尽。

    这有什么实际的后果?

    如果一个微任务recursion地排队其他微任务,则可能需要很长时间才能处理下一个macros任务。 这意味着,您的应用程序中可能会终止一个阻塞的UI,或者一些I / O空闲。

    不过,至less在Node.js的process.nextTick函数中(这些函数将microtasks排队),通过process.maxTickDepth有一个内置的防止这种阻塞的保护。 该值被设置为默认值1000,在达到这个限制之后减less微任务的进一步处理,这允许处理下一个macros任务

    那么什么时候用什么?

    基本上,当你需要以同步方式asynchronous执行任务时(即在最近的将来执行这个(微)任务时)使用微任务 。 否则,坚持macrotasks

    例子

    macrotasks setTimeout,setInterval,setImmediate,requestAnimationFrame,I / O,UI呈现
    microtasks: process.nextTick,Promises,Object.observe,MutationObserver

    我写了一篇文章,包括交互式的例子https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/

    规范中的基本概念:

    • 事件循环有一个或多个任务队列(任务队列是macrotask队列)
    • 每个事件循环都有一个microtask队列。
    • 任务队列= macrotask队列!= microtask队列
    • 一个任务可能会被推入macrotask队列或microtask队列
    • 当一个任务被推入一个队列(微/macros)时,意味着准备工作已经完成,所以现在可以执行任务。

    而事件循环过程模型如下:

    当调用堆栈为空时,请执行以下步骤 –

    1. select任务队列中最旧的任务(任务A)
    2. 如果任务A为空(意味着任务队列为空),跳转到步骤6
    3. 将“正在运行的任务”设置为“任务A”
    4. 运行“任务A”(即运行callback函数)
    5. 设置“当前正在运行的任务”为空,删除“任务A”
    6. 执行微任务队列
      • (a)。selectmicrotask队列中最旧的任务(任务x)
      • (b)。如果任务x为空(表示微任务队列为空),则跳到步骤(g)
      • (c)。将“正在运行的任务”设置为“任务x”
      • (d)。运行“任务x”
      • (五)。设置“当前正在运行的任务”为空,删除“任务x”
      • (f)。select微任务队列中的下一个最旧的任务,跳到步骤(b)
      • (g)。完成微任务队列;
    7. 跳转到第1步。

    一个简化的过程模型如下:

    1. 运行macrotask队列中最旧的任务,然后将其删除。
    2. 运行微任务队列中的所有可用任务,然后删除它们。
    3. 下一轮:运行macrotask队列中的下一个任务(跳转第2步)

    要记住的东西:

    1. 当一个任务(在macrotask队列中)正在运行时,可能会注册新的事件。因此可能会创build新的任务。下面是两个新创build的任务:
      • promiseA.then()的callback是一个任务
        • promiseA被parsing/拒绝:任务将在当前循环的事件循环中被推入微任务队列中。
        • promiseA等待处理:任务将在未来一轮的事件循环中被推入微任务队列(可能是下一轮)
      • setTimeout(callback,n)的callback是一个任务,并且会被推入macrotask队列,甚至n是0;
    2. microtask队列中的任务将在当前轮中运行,而macrotask队列中的任务必须等待下一轮事件循环。
    3. 我们都知道“点击”,“滚动”,“ajax”,“setTimeout”…的callback是任务,但是我们也应该记住js代码作为一个整体脚本标记也是一个任务(macrotask)。