简体   繁体   English

解决承诺中的承诺顺序

[英]Resolve order of Promises within Promises

For the below code 对于下面的代码

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')
})

The output is 输出是

Inner Promise
Outer Promise

I thought the outer resolve would be the first to enter the JS Message Queue followed by the inner resolve. 我以为外部解析将是第一个进入JS Message Queue的内部解析。 However the JS Event Loop fires the Inner resolve first then followed by Outer resolve. 但是,JS事件循环会先触发内部解析,然后再触发外部解析。

What does Promise resolve do internally? 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). 简而言之,你得到你所看到的行为,因为.then()的方法inner()承诺首先运行之前.then()的方法outer()的承诺,因此它的处理程序得到第一个排队(走一步看一步以下是为什么的解释)。

What does Promise resolve do internally? Promise解决内部做什么?

resolve() changes the internal state of the promise to Fulfilled. resolve()将承诺的内部状态更改为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. 那时,如果已将任何.then()处理程序附加到Promise,则将它们添加到队列中,以便在堆栈展开并且Javascript的当前运行路径完成时将其执行,并将控制权返回给系统。 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. 请注意,在这种情况下(当您阅读下面的逐步分析时,您将看到),如果还没有注册任何.then()处理函数,则无法将任何内容添加到队列中。

I thought the outer resolve would be the first to enter the JS Message Queue followed by the inner resolve. 我以为外部解析将是第一个进入JS Message Queue的内部解析。 However the JS Event Loop fires the Inner resolve first then followed by Outer resolve. 但是,JS事件循环会先触发内部解析,然后再触发外部解析。

Promise resolve actions are not added to the queue. 承诺解决操作未添加到队列中。 resolve() is synchronous. resolve()是同步的。 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. 如果在兑现诺言时,已经注册了任何.then()处理函数,那么它们就是添加到队列中的内容。 But, in both your promises, at the moment each of your promises are resolved, there are no .then() handlers yet attached. 但是,在您的两个承诺中,当您的每个承诺都得到解决时,尚没有附加.then()处理.then() So, those .then() handlers won't be queued at the point the promise is resolved. 因此,那些.then()处理程序不会在承诺被解决的时候排队。 Instead, they will be queued later when the .then() method actually runs and registers them. 相反,它们将在.then()方法实际运行并注册时稍后排队。

Here's a bit of an analysis of how your code runs and a likely explanation: 以下是对代码运行方式的分析以及可能的解释:

  1. First you call outer() . 首先,您调用outer() This creates a Promise object and synchronously calls the promise executor callback you pass it. 这将创建一个Promise对象,并在您传递它时同步调用Promise执行程序回调。
  2. That callback calls resolve() which will queue up the calling of any currently attached .then() handlers. 该回调将调用resolve() ,这将使所有当前附加的.then()处理程序的调用排队。 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). 请注意,此刻的你打电话resolve()有没有.then()因为在此代码尚未处理outer().then()您仍在运行outer().then()有后尚未运行,因此实际上还没有什么要排队(这可能是您观察到的订购的关键-请继续阅读以获取更多详细信息)。
  3. Then, the code calls inner() . 然后,代码调用inner() That creates a new promise and then (still running synchronously) calls the promise executor callback you pass there which calls resolve() . 这将创建一个新的Promise,然后(仍在同步运行)调用您传递给其中的Promise执行程序回调,该回调调用resolve() Again, there are not yet any .then() handlers attached so there is still yet nothing else to schedule for future execution. 同样,还没有附加任何.then()处理函数,因此仍然没有其他要安排的执行时间。
  4. Now, the Promise executor inside of inner() returns and the .then() method is called on that promise inside of inner() . 现在, inner()内部的Promise执行程序返回,并在inner()内部的那个promise上调用.then()方法。 This promise has already been resolved so, when this .then() handler is called, the promise knows to schedule it to run in the future. 这个承诺已经解决,因此,当调用此.then()处理程序时,该承诺知道将其安排在将来运行。 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. 由于当堆栈仅解开平台代码时,所有.then()处理.then()都被异步调用,因此它不会立即运行,而是计划将其放在队列中以在将来运行。 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. 这完全取决于实现方式,该队列的工作方式(宏任务或微任务等),但是我们知道Promise规范可以保证它在当前正在执行的同步JS代码片段完成运行并返回控制后运行回到系统。
  5. Now inner() returns (code is still running synchronously). 现在inner()返回(代码仍在同步运行)。
  6. Now outer() returns and the .then() method in outer().then() runs. 现在.then() outer()返回,并且.then() outer().then().then()方法运行。 Just like in the previous example, when this .then() method is called, the host promise is already resolved. 就像在前面的示例中一样,当调用此.then()方法时,主机承诺已经解析。 So, the promise engine will schedule the .then() handler callback to be run by adding it to the queue. 因此,promise引擎会通过将.then()处理函数回调添加到队列中来安排其运行。
  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 before outer().then()`. 如果将第4和第6步中的这两个.then()处理程序按其运行顺序进行排队(这将是逻辑实现),那么您会看到inner()上的.then()处理程序先运行,然后运行.then() outer()上的.then()处理函数将运行,因为inner().then() ran first before external()。then()` inner().then() ran first before 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. 尽管outer()之前得到解决inner()时,当时的outer()得到解决,目前还没有.then()所以没事的时候就解决了将来执行调度附加的处理程序。 This is likely why even though it is resolved first, its .then() handlers don't run first. 这可能就是为什么即使先解决它的.then()处理程序也不会先运行的原因。 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. 一旦inner()outer()都解决了,首先运行inner的.then()方法,因此在计划运行.then()处理程序时会首先遇到.then() ,这就是您所观察到的。

You can get some additional context for what's going on by reading and studying these references: 您可以通过阅读和研究这些参考资料来了解正在发生的事情:

What is the order of execution in javascript promises JavaScript Promise中的执行顺序是什么

Difference between microtask and macrotask within an event loop context . 事件循环上下文中微任务与宏任务的区别


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: 如果您想更明确地指定将首先触发内部.then()处理程序,则可以将其链接到outer()承诺,如下所示:

 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') }) 

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. 如果要保证首先调用outer().then()处理函数,则必须选择一个不同的结构,因为该结构不会以任何方式强制执行该类型的顺序,并且除非遵循该方向,否则您有意识地延迟了inner()的运行(使用setTimeout()或类似的东西)或重组了代码。 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: 例如,如果您真的想进行重组以强制inner()最后运行,则可以在outer().then()处理程序中将其启动,如下所示:

 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(); }) 

I thought the outer resolve would be the first to enter the JS Message Queue followed by the inner resolve. 我以为外部解析将是第一个进入JS Message Queue的内部解析。

Yes, the "outer" promise is resolved first. 是的,“外部”承诺首先得到解决。 Put a console.log right next to the resolve call. console.log放在resolve调用旁边。
But no, the outer then callback is not put in the queue first because it installed after the inner then callback. 但是不,外部的then回调不会首先放在队列中,因为它是在内部的then回调之后安装的。 What you are doing is essentially equivalent to 您所做的基本上等于

var outer = Promise.resolve();
var inner = Promise.resolve();
inner.then(function() {
    console.log('Inner Promise')
});
outer.then(function(data) {
    console.log('Outer Promise')
});

but obfuscated due to the nested (synchronous) function calls. 但由于嵌套(同步)函数调用而变得混乱。

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

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