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

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

问题描述

对于以下代码

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在内部解决了什么?

What does Promise resolve do internally?

推荐答案

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

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).


什么承诺在内部解决吗?

What does Promise resolve do internally?

resolve()更改内部状态实现的承诺。此时,如果已经附加到promise的任何 .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消息
队列,然后是内部解析。然而,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.

未添加承诺解决操作队列。 resolve()是同步的。它立即将当前承诺的状态更改为Fulfilled状态。如果在解析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()。这会产生一个新的承诺,然后(仍然同步运行)调用你传递的promise执行器回调调用 resolve()。同样,还没有附加任何 .then()处理程序,因此仍然没有其他任何可以安排以供将来执行。

  4. 现在, inner()内的Promise执行程序返回,并在该promise中调用 .then()方法 inner()。此承诺已经解决,因此,当调用此 .then()处理程序时,承诺知道将其安排在将来运行。由于当堆栈仅展开到平台代码时,所有 .then()处理程序都是异步调用的,因此它不会立即运行,而是计划在将来通过puttiing运行它在队列中。它的实现依赖于这个队列的工作原理(宏任务或微任务等等),但是我们知道Promise规范可以保证它在执行的当前同步JS代码之后运行并完成运行并返回控制回到系统。

  5. 现在 inner()返回(代码仍在同步运行)。

  6. 现在 outer()返回&外部的 .then()方法( ).then()运行。与前面的示例一样,当调用此 .then()方法时,主机承诺已经解决。因此,promise引擎将通过将其添加到队列来安排 .then()处理程序回调。

  7. 如果这些两个 .then()步骤4和6中的处理程序按照它们运行的​​顺序排队(这将是逻辑实现),然后你会看到 .then()处理器 inner()首先运行,然后运行 .then() c> outer()上的$ c>处理程序将在 inner()之后运行。然后()在 outer()之前先运行。然后()`。这就是你观察到的。

  8. 即使 outer() inner()是,当 outer()被解析时,没有 .then()附加处理程序所以没有什么可以安排在将来执行时解决。这可能是为什么即使先解决它,它的 .then()处理程序也不会先运行。一旦解析了 inner() outer(),它就是内部的 .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承诺中的执行顺序是什么

事件循环上下文中微任务和宏任务之间的差异

如果你想要更明确地指定内部 .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()。那么()处理程序首先被调用,你必须选择一个不同的结构,因为这个结构不会以任何方式强制这种类型的顺序,除非你有意识地延迟 inner的运行,否则不能被这个方向强行( )(使用 setTimeout()或某些此类事物)或重构代码。例如,如果你真的想重组以迫使 inner()最后运行,你可以在 outer()中启动它。然后( )这样的处理程序:

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中解决Promise的顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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