以下代码
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事件循环首先触发内部解析,然后是外部解析。
Promise在内部解决了什么?
答案 0 :(得分:6)
简而言之,您获得了所看到的行为,因为.then()
承诺上的inner()
方法首先在.then()
承诺上的outer()
方法之前运行,因此它& #39; s处理程序首先排队(请参阅下面的分步说明,了解其原因)。
Promise在内部解决了什么?
resolve()
将承诺的内部状态更改为已实现。此时,如果已经附加到promise的任何.then()
处理程序,它们将被添加到队列中,以便在堆栈展开并且Javascript的当前运行路径完成并将控制权返回给系统时执行。请注意,正如您将在本案例中看到的那样(当您阅读下面的逐步分析时),如果还没有任何已注册的.then()
处理程序,则无法将任何内容添加到队列中。
我认为外部决心将是第一个进入JS消息 队列之后是内在的决心。但是JS Event Loop会触发 首先是内心的决心,然后是外面的决心。
Promise解决操作未添加到队列中。 resolve()
是同步的。它立即将当前承诺的状态更改为Fulfilled状态。如果在解析promise时,已经注册了任何.then()
个处理程序,那么它们就是添加到队列中的内容。但是,在你的承诺中,在你的每一个承诺得到解决的那一刻,还没有附加.then()
个处理程序。因此,那些.then()
处理程序在承诺解决时不会排队。相反,当.then()
方法实际运行并注册它们时,它们将在稍后排队。
这里有一些关于代码如何运行的分析以及可能的解释:
outer()
。这将创建一个Promise对象并同步调用您传递它的promise executor回调。 resolve()
,它将排队调用任何当前连接的.then()
处理程序。请注意,在您拨打resolve()
时,尚未设置.then()
个处理程序,因为在此代码outer().then()
中,您仍在运行outer()
和{{ 1}}之后还没有运行,所以实际上还没有排队的东西(这可能是你观察到的顺序的关键 - 请继续阅读以获取更多细节)。.then()
。这会创建一个新的promise,然后(仍然同步运行)调用你在那里调用inner()
的promise执行者回调。同样,还没有附加任何resolve()
个处理程序,因此仍然没有其他任何可以安排以供将来执行。.then()
内的Promise执行程序返回,并在inner()
内的该承诺上调用.then()
方法。此承诺已经解决,因此,当调用此inner()
处理程序时,承诺知道将其安排在将来运行。由于当堆栈仅展开到平台代码时,所有.then()
处理程序都是异步调用的,因此它不会立即运行,而是计划在将来通过将其放入队列来运行。它的实现依赖于这个队列的工作原理(宏任务或微任务等等),但是我们知道Promise规范可以保证它在执行的当前同步JS代码之后运行并完成运行并返回控制回到系统。.then()
返回(代码仍在同步运行)。inner()
返回,outer()
中的.then()
方法运行。与前面的示例一样,当调用此outer().then()
方法时,主机承诺已经解决。因此,promise引擎将通过将.then()
处理程序回调添加到队列来安排运行.then()
处理程序回调。.then()
处理程序按照它们运行的顺序排队(这将是逻辑实现),那么您将在{{1}上看到.then()
处理程序首先运行,然后inner()
上的.then()
处理程序将从outer()
outer()。then()`开始运行。这就是你观察到的。inner().then() ran first before
之前已解决outer()
,但在解析inner()
时,仍未附加outer()
个处理程序,因此没有任何内容可供日后执行何时解决。这可能是为什么即使它首先被解决,它的.then()
处理程序也不会先运行。一旦.then()
和inner()
都得到解决,它就会首先运行内部outer()
方法,因此它会在安排.then()
处理程序运行时获得第一次破解,这就是你观察到的。通过阅读和研究这些参考资料,您可以获得一些额外的背景信息:
What is the order of execution in javascript promises
Difference between microtask and macrotask within an event loop context
如果您想更明确地指定内部.then()
处理程序首先触发,您可以简单地将其链接到.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')
})
处理程序,则必须选择不同的结构,因为此结构不会以任何方式强制执行此类订单,并且不能除非你有意识地延迟outer().then()
的运行(使用inner()
或某些此类事情)或重组代码,否则不要被这个方向哄骗。例如,如果您真的想要重组以强制setTimeout()
最后运行,那么您可以在inner()
处理程序中将其启动,如下所示:
outer().then()

答案 1 :(得分:1)
我认为外部决心将是第一个进入JS Message Queue,然后是内部决心。
是的,首先解决“外部”承诺。在console.log
电话旁边放resolve
但不是,外部然后回调没有首先放入队列,因为它安装在内部然后回调之后。你在做什么基本上等同于
var outer = Promise.resolve();
var inner = Promise.resolve();
inner.then(function() {
console.log('Inner Promise')
});
outer.then(function(data) {
console.log('Outer Promise')
});
但由于嵌套(同步)函数调用而混淆。