繁体   English   中英

为什么我的异步 function 在之前的 promise 被执行之前被执行?

[英]Why is my async function being executed before an earlier promise is being fulfilled?

我编写了一个小程序来比较.then()方法和async/await方法之间的承诺的履行情况。 代码运行正常,但是,收到的 output 顺序出乎意料。 有人可以解释为什么 output 处于当前订单中吗?

 const backend = (num) => { const someVar = new Promise((resolve, reject) => { if (num % 2 === 0) { resolve(`The number, ${num}, is even.`); } else { reject(`The number, ${num}, is odd.`); } }) return someVar; } const builtInFuncs = (num) => { backend(num).then(message => console.log(message)).catch(message => console.log(message)); } const asyncAwait = async(num) => { try { const response = await backend(num); console.log(response); } catch (error) { console.log(error); } } builtInFuncs(2); builtInFuncs(3); asyncAwait(4); asyncAwait(5);

我期望的 output 是:

The number, 2, is even.
The number, 3, is odd.
The number, 4, is even.
The number, 5, is odd.

我收到的 output 是:

The number, 2, is even.
The number, 4, is even.
The number, 5, is odd.
The number, 3, is odd.

对于微任务解析,每个方法调用都单独排队。 所以执行顺序是这样的:

  • 首次通话入队
  • 第二次呼叫排队
  • 第三次呼叫排队
  • 第四次呼叫入队
  • 首先.then触发,console.logged。
  • 第二个.then触发、拒绝、 .catch处理程序队(未调用)。
  • 调用 async/await,console.logged
  • 第二次调用 async/await,拒绝,catch 块入队。
  • .catch解析,console.logged。
  • catch 块解析,最终日志。

在评论中向 Barmar 提出关于切换接球顺序的想法的建议。

为了更简单地说明(清楚地?),考虑一个计数器和一个 Promise function 递增然后递减:

let i = 0;
const log = Promise.resolve()
  .then(() => console.log(++i))
  .then(() => console.log(--i));

log();
log();

这将打印 1 2 1 0 而不是 1 0 1 0。如果您考虑一下,这有一定的意义:方法链可能在任何步骤失败,因此运行时将第一个调用和第二个.then排入队列一旦第一个完成,就会排队。 否则,如果第一次调用失败(被拒绝),它将不得不返回 go 并从回调队列中删除推测性排队的第二次调用。

在我们得到答案之前,值得一提的是,依赖异步调用的执行顺序并不是一个好习惯。 有两种方法可以实现您的预期行为。 首选方法应该是:

(async() => {
   await builtInFuncs(2);
   await builtInFuncs(3);
   await asyncAwait(4);
   await asyncAwait(5);
})();

或者,您可以依赖 ECMAScript 标准保证的 PromiseReactionJobs 的执行顺序。 您需要将 builtInFuncs 重新定义为:

const builtInFuncs = (num) => {
   backend(num).then(
      message => console.log(message),
      message => console.log(message)
   );
}

请注意,onFulfilled 和 onRejected 处理程序都传递给.then() function。

观察到的执行顺序的实际原因非常复杂,但会发生以下情况:

  1. builtInFuncs(2)被调用

  2. builtInFuncs(2)调用backend(2).then()

  3. backend(2).then()实际上将console.log(2)排入队列

  4. backend(2).then()返回一个promise (比如promise1

  5. backend(2).then().catch()注意到onRejected上的promise1处理程序

  6. builtInFuncs(3)被调用

  7. builtInFuncs(3)调用backend(3).then()

  8. backend(3).then()将一个虚拟onRejected处理程序排入队列,因为没有指定

  9. backend(3).then()返回一个promise (比如promise2

  10. backend(3).then().catch()注意到onRejected处理程序在promise2上调用console.log(3)

  11. asyncAwait(4)被调用

  12. asyncAwait(4)有效地调用backend(4).then()

  13. backend(4).then()将继续尝试分支的 onFulfilled 处理程序排入队列

  14. asyncAwait(5)被调用

  15. asyncAwait(5)有效地调用backend(5).then()

  16. backend(5).then()将一个 onRejected 处理程序排入队列,该处理程序继续捕获分支

  17. 打印console.log(2)的处理程序出队

  18. 虚拟onRejected处理程序出队

  19. promise2onRejected处理程序排入队列,它注意到打印console.log(3)

  20. 继续尝试分支的 onFulfilled 处理程序被出列

  21. 继续 catch 分支的 onRejected 处理程序被出列

  22. 打印console.log(3)的处理程序出队

注意backend返回的promise立即解决或拒绝。 如果不是,则涉及更多步骤,但实际上观察到相同的行为。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM