gpt4 book ai didi

node.js - process.nextTick 和 queueMicrotask 的区别

转载 作者:行者123 更新时间:2023-12-01 10:19:27 25 4
gpt4 key购买 nike

Node 11.0.0 添加 queueMicrotasks作为实验。 doc说它类似于 process.nextTick但队列由 V8 而不是 Node.js 管理。使用的用例是什么 queueMicrotasks而不是 process.nextTick ?使用一种比另一种会有任何性能提升吗?

最佳答案

队列

我们可以找到不同的队列(在完成函数/脚本执行后按检查优先级顺序显示):

  • nextTick
  • 微任务
  • 计时器(已过期)
  • 立即

  • 如何检查队列?

    首先,检查 nextTick 队列以获取任务执行,一旦耗尽,检查 microTasks 队列。微任务队列中的任务完成后的检查过程
    nextTick 和 microTasks 队列被重复,直到队列被清空。

    下一个要检查的队列是计时器,最后是立即队列。

    差异

    是一样的,两者的方式都是在当前函数或脚本执行后才执行任务。

    他们有不同的队列。 nextTick 的队列由 Node 管理,微任务由 v8 管理。

    这是什么意思?

    在当前函数/脚本执行后首先检查 nextTick 队列,然后是 microTask 队列。

    没有性能提升,区别在于在函数/脚本执行后将首先检查 nextTick 队列,并且必须考虑到这一点。
    如果您从不使用 nextTick 并且只使用 queueMicrotask 您将拥有与仅使用 nextTick 相同的行为(考虑到您的任务将与另一个微任务一起放入队列中)

    用例可能是在任何微任务之前执行任务,例如,在 promise then 和/或 catch 之前。值得注意的是,promise 使用微任务,因此,添加到 then/catch 的任何回调都将添加到微任务队列中,并在 nextTick 队列为空时执行。

    例子

    执行这段代码后:
    function task1() {
    console.log('promise1 resolved');
    }

    function task2() {
    console.log('promise2 resolved');
    process.nextTick(task10);
    }

    function task3() {
    console.log('promise3 resolved');
    }

    function task4() {
    console.log('immediate 1');
    }

    function task5() {
    console.log('tick 1');
    }

    function task6() {
    console.log('tick 2');
    }

    function task7() {
    console.log('microtask 1');
    }


    function task8() {
    console.log('timeout');
    }


    function task9() {
    console.log('immediate 2');
    }

    function task10() {
    console.log('tick3');
    queueMicrotask(task11);
    }

    function task11() {
    console.log('microtask 2');
    }

    Promise.resolve().then(task1);
    Promise.resolve().then(task2);

    Promise.resolve().then(task3);

    setImmediate(task4);

    process.nextTick(task5);
    process.nextTick(task6);

    queueMicrotask(task7);

    setTimeout(task8, 0);

    setImmediate(task9);

    执行
  • nextTick: task5 |任务6
  • 微任务:task1 |任务2 |任务3 |任务7
  • 计时器:task8
  • 立即:task4 |任务 9

  • 第一步:执行nextTick队列中的所有任务
  • nextTick: 空
  • 微任务:task1 |任务2 |任务3 |任务7
  • 计时器:task8
  • 立即:task4 |任务 9

  • 输出:
  • 刻度 1
  • 刻度 2

  • 第二步:执行microTasks队列中的所有任务
  • nextTick: task10
  • 微任务:空
  • 计时器:task8
  • 立即:task4 |任务 9

  • 输出:
  • 刻度 1
  • 刻度 2
  • promise 1 已解决
  • promise 2 已解决
  • promise 3 已解决
  • 微任务 1

  • 第三步:执行nextTick队列中的所有任务(微任务(task2)的执行增加了一个新任务)
  • nextTick: 空
  • 微任务:task11
  • 计时器:task8
  • 立即:task4 |任务 9

  • 输出:
  • 刻度 1
  • 刻度 2
  • promise 1 已解决
  • promise 2 已解决
  • promise 3 已解决
  • 微任务 1
  • 刻度 3

  • 第四步:执行microTasks队列中的所有任务(task10的执行增加了一个新任务)
  • nextTick: 空
  • 微任务:空
  • 计时器:task8
  • 立即:task4 |任务 9

  • 输出:
  • 刻度 1
  • 刻度 2
  • promise 1 已解决
  • promise 2 已解决
  • promise 3 已解决
  • 微任务 1
  • 刻度 3
  • 微任务 2

  • 第五步:nextTick 和 microTasks 队列中不再有任务,next 执行定时器队列。
  • nextTick: 空
  • 微任务:空
  • 定时器:空
  • 立即:task4 |任务 9

  • 输出:
  • 刻度 1
  • 刻度 2
  • promise 1 已解决
  • promise 2 已解决
  • promise 3 已解决
  • 微任务 1
  • 刻度 3
  • 微任务 2
  • 超时

  • 第 6 步:(过期)定时器队列中不再有任务,执行立即队列中的任务
  • nextTick: 空
  • 微任务:空
  • 定时器:空
  • 立即:空

  • 输出:
  • 刻度 1
  • 刻度 2
  • promise 1 已解决
  • promise 2 已解决
  • promise 3 已解决
  • 微任务 1
  • 刻度 3
  • 微任务 2
  • 超时
  • 立即 1
  • 即时 2

  • 正如我们所看到的,选择一个或另一个没有性能原因,选择的决定取决于我们的需求以及需要做什么以及何时完成。

    想象一下这段代码:
    let i = 1;

    queueMicrotask(() => console.log(i));
    process.nextTick(() => i++);

    由于首先首先检查 nextTick 队列,因此输出将为 2。

    但如果你这样做
    let i = 1;

    queueMicrotask(() => console.log(i));
    process.nextTick(() => queueMicrotask(() =>i++));

    你会得到1。

    通过示例,我想让您看到用例来自您对需要执行任务的内容和时间的需求。重要的是考虑到 promise 中的 then/catch 回调是微任务,将在 nextTick 任务之后执行,考虑到这对于避免错误很重要(如后面的示例中所述)。

    关于node.js - process.nextTick 和 queueMicrotask 的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55467033/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com