本文介绍了为什么这个异步函数会在它之前定义的等价 Promise.then 链之前执行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码:

var incr = num => new Promise(resolve => {
  resolve(num + 1);
});

var x = incr(3)
  .then(resp => incr(resp))
  .then(resp => console.log(resp));

async function incrTwice(num) {
  const first = await incr(num);
  const twice = await incr(first);
  console.log(twice);
}

incrTwice(6);

我认为(可能是错误的)展示了实现相同功能的两种等效方法:第一种是通过链接 promise,第二种是使用 async/await 的语法糖.

Which I believe (perhaps mistakenly) shows two equivalent ways to achieve the same functionality: first by chaining promises and second with the syntactic sugar of async/await.

我希望promise链接解决方案首先打印到console.log,然后是异步函数,但是异步函数console.log的第一个然后promise链接解决方案打印.

I would expect the promise chaining solution to console.log first, then the async function second, however the async function console.log's first then the promise chaining solution prints.

我的逻辑如下:

  1. x 的初始解析将在处理声明时首先出现在微任务队列中
  2. xincrTwice 的声明之间的堆栈是空的,这会导致微任务队列被刷新(导致承诺链的完成)
    • x 先打印
  1. xs initial resolve would be first on the microtask queue as the declaration is processed
  2. the stack is empty between the declaration of x and incrTwice which would cause the microtask queue to be flushed (resulting in the completion of the promise chain)
    • x prints first
  • incrTwice 打印秒

显然我在某处有误解,有人能指出我错在哪里吗?

Clearly I have a misunderstanding somewhere, is someone able to point out where I am wrong?

推荐答案

首先,我要指出,你永远不应该争论独立 promise 链的执行顺序.有两个异步调用,它们不相互依赖而是并发运行,因此应该总是期望它们以任意顺序完成.

First of all, let me point out that you never should argue about the execution order of independent promise chains. There are two asynchronous calls, and they do not depend on each other but run concurrently, so they should always be expected to finish in arbitrary order.

仅使用立即解决承诺的玩具示例使此顺序依赖于微任务队列语义而不是实际的异步任务,这使得这成为纯粹的学术练习(其 结果可能会在规范中发生变化).

Toy examples that only use immediately-resolving promises make this order depend on microtask queueing semantics instead of actual asynchronous tasks, which makes this a purely academic exercise (whose result is subject to changes in the spec).

无论如何,让我们消除你的误解:

Anyway, let's clear up your misunderstandings:

xincrTwice 声明之间的栈是空的,这会导致微任务队列被刷新

不,只有在所有用户代码运行完成后,堆栈才会变空.堆栈上仍然有 元素的全局执行上下文.在所有同步代码(incr = …x = incr(3).…incrTwice(6))完成之前,不会执行任何微任务.

No, the stack only becomes empty after all user code is ran to completion. There's still the global execution context of the <script> element on the stack. No microtasks are executed until all synchronous code (incr = …, x = incr(3).… and incrTwice(6)) has finished.

我相信 [代码] 展示了实现相同功能的两种等效方法:第一种是通过链接 promise,第二种是使用 async/await 的语法糖.

不完全是.在取消从第一个 .then(...)incr(resp) 承诺时,.then() 链接有一个额外的解析步骤> 处理程序.为了使它的行为与 incrTwice 中的 awaited 承诺完全相同,您需要编写

Not exactly. The .then() chaining has an additional resolve step when unnesting the incr(resp) promise that is returned from the first .then(…) handler. To make it behave precisely the same as the awaited promises in incrTwice, you'd need to write

incr(3).then(resp =>
  incr(resp).then(resp =>
    console.log(resp)
  )
);

如果这样做,您实际上会按照启动两个承诺链的顺序获得 console 日志,因为它们将执行相同数量的微任务,直到 控制台.log() 被执行.

If you do that, you'll actually get the console logs in the order in which you started the two promise chains because they will take the same number of microtasks until the console.log() is executed.

更多细节参见javascript promises中的执行顺序是什么解决 Promises 中 Promises 的顺序, 当我们返回一个值时会发生什么而当我们从 then() 链中返回一个 Promise.resolve 时,在微任务队列中?有什么区别返回 Promise?, ES6 Promise 返回值的执行顺序

For more details, see What is the order of execution in javascript promises, Resolve order of Promises within Promises, What happen when we return a value and when we return a Promise.resolve from a then() chain, in the microtask queue?, What is the difference between returned Promise?, ES6 promise execution order for returned values

这篇关于为什么这个异步函数会在它之前定义的等价 Promise.then 链之前执行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-18 11:26