然后在JS Promise上有多个链?

时间:2018-08-25 10:09:19

标签: javascript typescript promise es6-promise

今天,我尝试了将多个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

3 个答案:

答案 0 :(得分:1)

好的,我想我理解在评论中对Jaromanda X进行一些澄清之后会发生什么!

这是完全确定性的!

承诺将回调添加到所谓的“ 微任务”堆栈中。除了其他JS堆栈之外,那些Microtasks会在JS堆栈为空(所有同步代码都完成)时运行...请参阅Jaromanda X发布的视频中的注释!

所以它是这样的:

  • “ then1”已添加到MT堆栈
  • test()返回
  • “ then2”已添加到MT堆栈

同步代码已完成!微任务时间!

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池应该在作业队列中排队。