Promise 和 setTimeout 优先级

问题描述 投票:0回答:2

我一直在与这个疑问作斗争,因为在事件循环中,作业队列比回调队列具有更高的优先级,即,promise 比 setTimeout 具有更高的优先级,那么呢:

new Promise(resolve => setTimeout(resolve, 0, "Done!")).then((message) => console.log(message));

下面的代码中它的优先级是如何决定的:

function f1() {
    console.log('f1');
}

function f2() {
    console.log('f2');
}

function f3(){
    console.log('f3');
}

function f4(){
    console.log('f4');
}

function main() {
    console.log('main');

    setTimeout(f1, 0);
    Promise.resolve().then(() => console.log('r1'));

    new Promise(resolve => setTimeout(resolve, 0, "Done!")).then((message) => console.log(message));

    f2();
    console.log('hello');
    setTimeout(f3, 0);
}

setTimeout(f4, 0);
main();

输出为:

main
f2
hello
r1
f4
f1
Done!
f3
javascript promise settimeout event-loop
2个回答
2
投票

执行顺序:

  1. main()
    中的同步代码首先执行:

    • console.log('main');
      打印
      main
    • setTimeout(f1, 0);
      f1
      安排为宏任务。
    • Promise.resolve().then(() => console.log('r1'));
      安排一个微任务来打印
      r1
    • new Promise(resolve => setTimeout(resolve, 0, "Done!")).then((message) => console.log(message));
      安排一个宏任务来解决承诺。
    • f2();
      打印
      f2
    • console.log('hello');
      打印
      hello
    • setTimeout(f3, 0);
      f3
      安排为宏任务。
  2. 外部同步代码

    main()

    • setTimeout(f4, 0);
      f4
      安排为宏任务。
  3. 接下来处理微任务(promise):

    • Promise.resolve().then(() => console.log('r1'));
      打印
      r1
  4. 宏任务按照计划的顺序进行处理:

    • f4
      打印
      f4
    • f1
      打印
      f1
    • 新的
      setTimeout
      中的
      Promise
      解决的承诺会打印
      Done!
    • f3
      打印
      f3

0
投票

这里没有优先顺序。优先级是指允许用户代理 (UA) 选择哪个任务先于另一个任务运行。

对于微任务,它们根本没有选择,当 JS 调用堆栈为空时,它必须执行下一个微任务,无论 JS 是从任务内部执行、在回调执行之后还是在另一个微任务执行之后。

优先级是一件任务的事情,当事件循环从各种任务源中选择一个时(这个算法中的步骤2.1)。例如,UI任务通常比超时任务具有更高的优先级,因此如果同时存在待处理的UI任务和待处理的超时任务,则UA将首先执行UI任务。如果这样运行 JS,每次 JS 调用堆栈为空时都会有一个微任务检查点

所以当你这样做时

new Promise(resolve => setTimeout(resolve, 0, "Done!"))
.then((message) => console.log(message));

超时任务将执行解析 Promise 的 JS,解析 Promise 会将执行记录消息的 JS 的微任务排队。超时任务中的 JS 执行结束后,由于 JS 调用栈为空,该微任务会“直接”执行。因此,这意味着负责执行记录消息的 JS 的微任务本身就是“计时器任务内部”。只有在该微任务运行完成后,UA 才会继续执行其必须执行的剩余步骤以结束计时器任务。 因此,正如您所看到的,微任务与任务并不对立,它们是不同的东西,尽管两者都允许规范使 UA 执行东西,但整个事件循环的处理模型也是如此。谈论这些不同事情的优先级是没有意义的,因为它们的执行时间是不具有可比性的。

© www.soinside.com 2019 - 2024. All rights reserved.