今天,我尝试了将多个then链添加到Promise中时发生的情况。我的测试代码如下所示(TypeScript)
class Test {
private simulateHeavyStuff(time: number){
// console.log("-"+time+"-");
var start = new Date().getTime();
var end = start;
while(end < start + time) {
end = new Date().getTime();
}
}
test(): Promise<void> {
let promise = new Promise<void>((resolve, reject) => {
resolve();
});
// ##### ADDING CHAIN 1 #####
promise
.then(()=>console.log("then1"))
.then(()=>this.simulateHeavyStuff(2000))
.then(()=>console.log("then11"))
.catch(console.error)
return promise;
}
}
let t = new Test();
// ##### ADDING CHAIN 2 #####
t.test()
.then(()=>console.log("then2"))
.then(()=>console.log("then21"))
.catch(console.error)
打印输出:
then1
then2
<---it's pausing here
then21
then11
有人可以解释这种行为背后的确定性吗?
我认为它可以打印(平行链)
then1
then2
then21
<--- I guessed the pause will be here
then11
或(一个链)
then1
<--- with the pause here
then11
then2
then21
答案 0 :(得分:1)
好的,我想我理解在评论中对Jaromanda X进行一些澄清之后会发生什么!
这是完全确定性的!
承诺将回调添加到所谓的“ 微任务”堆栈中。除了其他JS堆栈之外,那些Microtasks会在JS堆栈为空(所有同步代码都完成)时运行...请参阅Jaromanda X发布的视频中的注释!
所以它是这样的:
同步代码已完成!微任务时间!
MT堆栈现在看起来像这样
then1
then2
因此,然后运行1并在MT堆栈返回Promise时将另一个Microtask添加到MT堆栈。 MT堆栈现在看起来像这样
then2
heavyStuff(2000)
随着进一步的微任务运行,直到MT堆栈为空,此操作将一直持续到所有MT完成为止。然后其他任何代码都继续下去...
答案 1 :(得分:0)
这是因为您的方法test
返回了promise
变量,该变量与其中的catch
返回的结果不同,因此,当您调用.test()
时,它将不要等待test
中的整个链条。
如果您更改
promise
.then(()=>console.log("then1"))
.then(()=>this.simulateHeavyStuff(2000))
.then(()=>console.log("then11"))
.catch(console.error)
到
promise = promise
.then(()=>console.log("then1"))
.then(()=>this.simulateHeavyStuff(2000))
.then(()=>console.log("then11"))
.catch(console.error)
它将按预期工作。
答案 2 :(得分:-1)
答案似乎是您(可能是错误地)创建了两个承诺(因为.then
根据前一个创建了一个 new 承诺对象,请参见MDN) 。看看下面的评论:
test(): Promise<void> {
// this creates the base promise "A"
let promise = new Promise((resolve, reject) => {
resolve();
});
// this creates promise "A1" by adding a chain of operations to "A"
// you are not returning it however
promise
.then(()=>console.log("then11"))
.then(()=>console.log("then12"))
.then(()=>this.simulateHeavyStuff(2000))
.then(()=>console.log("then14"))
.catch(console.error)
// this returns "A" (not "A1")
return promise;
}
// this creates promise "A2"
t.test()
.then(()=>console.log("then2"))
.then(()=>console.log("then21"))
.catch(console.error)
运行代码段时,您会发现round-robin principle似乎完全确定地完成了两个诺言的处理(这意味着对每个.then
操作步骤都依次执行了诺言) 。顺序是
“ A1”->“ A2”->“ A1” ...
class Test {
simulateHeavyStuff(time){
// console.log("-"+time+"-");
var start = new Date().getTime();
var end = start;
while(end < start + time) {
end = new Date().getTime();
}
console.log('then13 (heavy stuff)');
}
test() {
let promise = new Promise((resolve, reject) => {
resolve();
});
// ##### ADDING CHAIN 1 #####
promise
.then(()=>console.log("then11"))
.then(()=>console.log("then12"))
.then(()=>this.simulateHeavyStuff(2000))
.then(()=>console.log("then14"))
.catch(console.error)
return promise;
}
}
let t = new Test();
// ##### ADDING CHAIN 2 #####
t.test()
.then(()=>console.log('then21'))
.then(()=>console.log('then22'))
.then(()=>console.log('then23'))
.catch(console.error)
在您的情况下-所有执行步骤都是完全同步的-程序正在确定地执行:即,许诺“ A1”的 i 链式.then
操作在< em> i 的“ A2”的链式.then
操作;并且承诺“ A1”的 i + 1 链式.then
操作遵循承诺“ A2”的第 i 链式.then
操作。 / p>
ECMA Script 2015 specification似乎证实了此行为,因为.then
池应该在作业队列中排队。