解决 Promises 中 Promises 的顺序 [英] Resolve order of Promises within Promises

查看:19
本文介绍了解决 Promises 中 Promises 的顺序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于下面的代码

function inner () {
  new Promise(function(resolve,reject){
    resolve()
  }).then(function(){
    console.log('Inner Promise')
  })
}
function outer() {
  return new Promise(function(resolve, reject){
    resolve()
    inner()
  })
}

outer().then(function(data) {
  console.log('Outer Promise')
})

输出是

Inner Promise
Outer Promise

我认为外部解析会首先进入 JS 消息队列,然后是内部解析.然而,JS 事件循环首先触发内部解析,然后是外部解析.

I thought the outer resolve would be the first to enter the JS Message Queue followed by the inner resolve. However the JS Event Loop fires the Inner resolve first then followed by Outer resolve.

Promise resolve 在内部做了什么?

What does Promise resolve do internally?

推荐答案

简而言之,您会得到您所看到的行为,因为 inner()<上的 .then() 方法/code> 承诺首先在 outer() 承诺上的 .then() 方法之前运行,因此它的处理程序首先排队(请参阅下面的分步说明,了解为什么会这样是).

In a nutshell, you get the behavior you see because the .then() method on the inner() promise runs first before the .then() method on the outer() promise and thus it's handler gets queued first (see step by step explanation below for why this is).

Promise resolve 在内部做了什么?

What does Promise resolve do internally?

resolve() 将承诺的内部状态更改为已完成.此时,如果有任何 .then() 处理程序已经附加到承诺,它们将被添加到一个队列中,以便在堆栈展开和 Javascript 的当前运行路径完成并返回控制权时执行回到系统.请注意,正如您在本例中看到的(当您阅读下面的分步分析时),如果还没有注册任何 .then() 处理程序,则还没有任何东西可以添加到队列中.

resolve() changes the internal state of the promise to Fulfilled. At that moment, if there are any .then() handlers already attached to the promise, they are added to a queue to be executed when the stack unwinds and the current running path of Javascript finishes and returns control back to the system. Note, as you will see in this case (when you read the step-by-step analysis below), if there are not yet any .then() handlers that have been registered, nothing can yet be added to the queue.

我以为外层解析会第一个进入JS Message队列后跟内部解析.但是 JS 事件循环会触发先内部解析,然后是外部解析.

I thought the outer resolve would be the first to enter the JS Message Queue followed by the inner resolve. However the JS Event Loop fires the Inner resolve first then followed by Outer resolve.

Promise 解析操作不会添加到队列中.resolve() 是同步的.它立即将当前承诺的状态更改为已完成状态.如果在 promise 被解析时,有任何 .then() 处理程序已经注册,那么它们就是被添加到队列中的.但是,在您的两个承诺中,在您的每个承诺都得到解决的那一刻,还没有附加 .then() 处理程序.因此,那些 .then() 处理程序不会在承诺解决时排队.相反,当 .then() 方法实际运行并注册它们时,它们将在稍后排队.

Promise resolve actions are not added to the queue. resolve() is synchronous. It changes the state of the current promise to the Fulfilled state immediately. If, at the time the promise is resolved, there are any .then() handlers already register, then they are what is added to a queue. But, in both your promises, at the moment each of your promises are resolved, there are no .then() handlers yet attached. So, those .then() handlers won't be queued at the point the promise is resolved. Instead, they will be queued later when the .then() method actually runs and registers them.

以下是对代码运行方式的一些分析以及可能的解释:

Here's a bit of an analysis of how your code runs and a likely explanation:

  1. 首先调用outer().这将创建一个 Promise 对象并同步调用您传递给它的 Promise Executor 回调.
  2. 该回调调用了 resolve(),它将对当前附加的任何 .then() 处理程序的调用进行排队.请注意,在您调用 resolve() 的那一刻,还没有 .then() 处理程序,因为在此代码中 outer().then(),您仍在运行 outer().then() ,因为它尚未运行,因此实际上还没有任何东西要排队(这可能是您观察到的顺序的关键 - 请继续阅读以了解更多详情).
  3. 然后,代码调用inner().这会创建一个新的承诺,然后(仍然同步运行)调用你传递的承诺执行器回调,它调用 resolve().同样,还没有附加任何 .then() 处理程序,因此仍然没有其他安排以供将来执行.
  4. 现在,inner() 内的 Promise 执行器返回,并且 .then() 方法在 inner() 内的那个 Promise 上被调用代码>.这个 promise 已经被解析,所以当这个 .then() 处理程序被调用时,promise 知道安排它在未来运行.由于所有 .then() 处理程序在堆栈展开为仅平台代码时异步调用,因此它不会立即运行,而是通过将其放入队列来安排在将来运行.它完全依赖于这个队列的工作方式(宏任务或微任务等),但我们知道它是由 Promise 规范保证在当前正在执行的同步 JS 代码完成运行并返回控制之后运行的回到系统.
  5. 现在 inner() 返回(代码仍在同步运行).
  6. 现在 outer() 返回并且 outer().then() 中的 .then() 方法运行.就像前面的例子一样,当这个 .then() 方法被调用时,宿主承诺已经被解析.因此,promise 引擎将通过将 .then() 处理程序回调添加到队列中来安排其运行.
  7. 如果第 4 步和第 6 步中的这两个 .then() 处理程序按照它们运行的​​顺序(这将是逻辑实现)排队,那么您将看到 .then() inner() 上的处理程序首先运行,然后 outer() 上的 .then() 处理程序将运行,因为 inner().then() 在outer().then()` 之前先运行.这就是你观察到的.
  8. 即使 outer()inner() 之前被解析,在 outer() 被解析时,没有 .then() 附加处理程序,因此在解决时没有任何安排供将来执行.这可能是为什么即使它首先被解析,它的 .then() 处理程序不会首先运行.一旦 inner()outer() 都解析了,那么首先运行的是inner的.then()方法,所以它首先被破解在安排 .then() 处理程序运行时,这就是您观察到的.
  1. First you call outer(). This creates a Promise object and synchronously calls the promise executor callback you pass it.
  2. That callback calls resolve() which will queue up the calling of any currently attached .then() handlers. Note, that at the moment you call resolve(), there are no .then() handlers yet because in this code outer().then(), you're still running outer() and the .then() after it has not yet run so there isn't actually yet anything to queue up yet (this is probably key to the ordering you observe - read on for further details).
  3. Then, the code calls inner(). That creates a new promise and then (still running synchronously) calls the promise executor callback you pass there which calls resolve(). Again, there are not yet any .then() handlers attached so there is still yet nothing else to schedule for future execution.
  4. Now, the Promise executor inside of inner() returns and the .then() method is called on that promise inside of inner(). This promise has already been resolved so, when this .then() handler is called, the promise knows to schedule it to run in the future. Since all .then() handlers are called asynchronously when the stack has unwound to only platform code, it is not run immediately, but it is scheduled to run in the future by puttiing it in a queue. It is implementation dependent exactly how this queue works (macro task or micro task, etc...), but we know it is guaranteed by the Promise specification to run after the current synchronous piece of JS code that is executing finishes running and returns control back to the system.
  5. Now inner() returns (code is still running synchronously).
  6. Now outer() returns and the .then() method in outer().then() runs. Just like in the previous example, when this .then() method is called, the host promise is already resolved. So, the promise engine will schedule the .then() handler callback to be run by adding it to the queue.
  7. If these two .then() handlers in steps 4 and 6 are queued in the order they were run (which would be the logical implementation), then you would see the .then() handler on inner() run first and then the .then() handler on outer() would run since inner().then() ran first beforeouter().then()`. That is what you observe.
  8. Even though outer() is resolved before inner() is, at the time outer() is resolved, there are not .then() handlers attached so there is nothing to schedule for future execution when it is resolved. This is likely why even though it is resolved first, its .then() handlers don't run first. Once both inner() and outer() are resolved, it is inner's .then() method that runs first, so it gets first crack at scheduling a .then() handler to run and this is what you observe.

通过阅读和研究这些参考资料,您可以获得一些关于正在发生的事情的额外背景:

You can get some additional context for what's going on by reading and studying these references:

javascript promise 中的执行顺序是什么

事件循环中微任务和宏任务的区别上下文.

如果您想更明确地指定内部 .then() 处理程序将首先触发,您可以简单地将其链接到 outer() 承诺,如下所示:

If you wanted to more explicitly specify that the inner .then() handler would fire first, you can simply chain it to the outer() promise like this:

function inner () {
  return new Promise(function(resolve,reject){
    resolve();
  }).then(function(){
    console.log('Inner Promise')
  })
}
function outer() {
    // Add return here to chain the inner promise
    // make to make sure that outer() does not resolve until
    // inner() is completely done
    return inner();
}

outer().then(function(data) {
  console.log('Outer Promise')
})

如果您想保证 outer().then() 处理程序首先被调用,您必须选择不同的结构,因为该结构不会强制任何类型的顺序除非你有意识地延迟 inner() 的运行(使用 setTimeout() 或类似的东西)或重构代码,否则不能被说服.例如,如果你真的想重组以强制 inner() 最后运行,你可以在 outer().then() 处理程序中启动它,如下所示:

If you wanted to guarantee that the outer().then() handler was called first, you'd have to pick a different structure since this structure does not force that type of order in any way and can't be cajoled that direction unless you consciously delay the running of inner() (using a setTimeout() or some such thing) or restructure the code. For example, if you really wanted to restructure to force inner() to run last, you would kick it off in the outer().then() handler like this:

function inner () {
  return new Promise(function(resolve,reject){
    resolve()
  }).then(function(){
    console.log('Inner Promise')
  })
}
function outer() {
  return new Promise(function(resolve, reject){
    resolve()
  })
}

outer().then(function(data) {
  console.log('Outer Promise')
  return inner();
})

这篇关于解决 Promises 中 Promises 的顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆