简体   繁体   English

然后在JS Promise上有多个链?

[英]Multiple chains of then on a JS Promise?

Today I tried out what happens when I add multiple chains of then to a Promise. 今天,我尝试了将多个then链添加到Promise中时发生的情况。 My test code looks like that (TypeScript) 我的测试代码如下所示(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)

This prints out: 打印输出:

then1
then2
        <---it's pausing here
then21
then11

Can someone explain the determinism behind this behavior? 有人可以解释这种行为背后的确定性吗?

I thought it would either print (parallel chains) 我认为它会打印(平行链)

then1
then2
then21
       <--- I guessed the pause will be here
then11

or (one chain) 或(一个链)

then1
       <--- with the pause here
then11
then2
then21

OK, I guess I understand what happens after some clarifications of Jaromanda X down in the comments! 好的,我想我知道在注释中对Jaromanda X进行一些澄清之后会发生什么!

It is fully deterministic! 这是完全确定性的!

Promises add the callbacks to the so called " Microtasks " stack. 承诺将回调添加到所谓的“ 微任务 ”堆栈中。 Other than other JS stacks those Microtasks run when the JS stack is empty (all synchronous code is done)...see the Video posted by Jaromanda X in the comments! 除了其他JS堆栈以外,那些Microtasks在JS堆栈为空(所有同步代码都已完成)时运行...请参阅Jaromanda X发布的视频中的注释!

So it happens like this: 所以它是这样的:

  • "then1" is added to the MT Stack “ then1”添加到MT堆栈
  • test() returns test()返回
  • "then2" is added to the MT Stack “ then2”添加到MT堆栈

Synchronous code is done! 同步代码完成! Microtasks time! 微任务时间!

The MT Stack looks like this now MT Stack现在看起来像这样

then1
then2

So then1 is run and adds another Microtask to the MT stack as it returns a Promise. 因此,然后运行1并在MT栈返回Promise时将另一个Microtask添加到MT栈。 The MT stack looks like this now MT堆栈现在看起来像这样

then2
heavyStuff(2000)

As further Microtasks are run until the MT stack is empty this goes on until all MTs are finished. 随着更多的微任务运行,直到MT堆栈为空,这将继续进行,直到所有MT都完成。 Then any other code goes on... 然后任何其他代码继续进行...

This is because your method test returns promise variable, that is not the same as result returned by catch in it, so when you call .test() , it will not wait the whole chain inside test . 这是因为方法test返回的promise变量与catch中返回的结果不同,因此,当您调用.test() ,它将不会等待test的整个链。

If you change 如果你改变

promise
    .then(()=>console.log("then1"))
    .then(()=>this.simulateHeavyStuff(2000))
    .then(()=>console.log("then11"))
    .catch(console.error)

to

promise = promise
    .then(()=>console.log("then1"))
    .then(()=>this.simulateHeavyStuff(2000))
    .then(()=>console.log("then11"))
    .catch(console.error)

it will work as you expected. 它会按预期工作。

The answer seems to be that you—probably by mistake—created two promises (since .then creates a new promise object based on the previous one, see MDN ). 答案似乎是您(可能是错误地)创建了两个Promise(因为.then根据前一个创建新的 Promise对象,请参见MDN )。 Have a look at the comments below: 看看下面的评论:

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)

When you run the code snippet you will see that the processing of both promises seems to be done fully deterministically by the round-robin principle (meaning that the promises are executed in turn for every .then operation step). 当您运行代码片段时,您会发现两个承诺的处理似乎都是通过循环原则完全确定地完成的(意味着对每个.then操作步骤依次执行承诺)。 The sequence is 顺序是

"A1" -> "A2" -> "A1" ... “ 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) 

In your case—where the execution steps are all fully synchronous—the program is being executed deterministically: ie the i -th chained .then operation of promise "A1" precedes the i -th chained .then operation of "A2"; 在你的情况,在执行步骤正在执行确定性都充分同步程序:即个链接的 .then的承诺“A1”操作之前个链接的 .then “A2”的操作; and the i+1 chained .then operation of promise "A1" follows the i -th chained .then operation of promise "A2". 和第i + 1.then的承诺“A1”的操作如下第链第i .then许的操作“A2”。

The ECMA Script 2015 specification seems to confirm this behavior since the .then pools are supposed to queued in a job queue. ECMA Script 2015规范似乎确认了此行为,因为.then池应该在作业队列中排队。

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

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