简体   繁体   English

这个 Promise 链发生了什么?

[英]What is happening with this chain of Promises?

I am scratching my head trying to understand what is happening with the following cases.我正在挠头试图了解以下情况发生了什么。

Case 1:情况1:

async function doSomething(): Promise<void> {
    return new Promise(resolve => {

        const promise = (async () => "A")();

        promise
            .then(() => {
                console.log("THEN");
                resolve();
            })
            .catch(() => {
                console.log("CATCH");
            })
            .finally(() => {
                console.log("FINALLY");
            });
    });
}

async function main() {
    await doSomething();
    console.log("DONE");
}

main().catch(console.error);

Output, as expected: Output,符合预期:

THEN
FINALLY
DONE

But in case 2:但在情况 2 中:

async function doSomething(): Promise<void> {
    return new Promise(resolve => {

        const promise = (async () => Promise.resolve("A"))();

        promise
            .then(() => {
                console.log("THEN");
                resolve();
            })
            .catch(() => {
                console.log("CATCH");
            })
            .finally(() => {
                console.log("FINALLY");
            });
    });
}

async function main() {
    await doSomething();
    console.log("DONE");
}

main().catch(console.error);

The output is: output 是:

THEN
DONE
FINALLY

And case 3:案例 3:

async function doSomething(): Promise<void> {
    return new Promise(resolve => {

        const promise = (async () => Promise.resolve("A"))();

        promise
            .then(() => {
                console.log("THEN");
                resolve();
            })
            .finally(() => {
                console.log("FINALLY");
            });
    });
}

async function main() {
    await doSomething();
    console.log("DONE");
}

main().catch(console.error);

The output is: output 是:

THEN
FINALLY
DONE

What is happening exactly to the chain of promises?承诺链到底发生了什么?

Why the case 2 doesn't print "THEN, FINALLY, DONE"?为什么案例 2 不打印“THEN, FINALLY, DONE”?

Why the case 3 behaves differently from case 2?为什么案例 3 的行为与案例 2 不同?

I might have understood what happened with the 3 cases.我可能已经明白这 3 个案例发生了什么。

TLDR TLDR

The difference in number of promises and the resolution of promises with promise changes the sequence of microtask enqueued causing the difference in print statements. promise 的承诺数量和承诺解决方案的差异改变了微任务排队的顺序,导致打印语句的差异。

Code simplification代码简化

First of all lets try to simplify the code removing the async/await.首先让我们尝试简化删除异步/等待的代码。 I will use the code of case 1 for the simplification.我将使用案例 1 的代码进行简化。

The main block主块

async function doSomething(): Promise<void> {
    return new Promise(resolve => {
        ...
    });
}
async function main() {
    await doSomething();
    console.log("DONE");
}

main().catch(console.error);

can be rewrote to:可以重写为:

function doSomething(): Promise<void> {
   // Promise A
   return new Promise(resolve => {
     // Promise B
     const b = new Promise(resolve => {
            ...
     });
     resolve(b);
   });
}

doSomething()
 .then(function externalThen() {
   console.log("DONE");
 });

The promise declaration for case 1:案例1的promise申报表:

const promise = (async () => "A")();

becomes:变成:

const promise = Promise.resolve("A");

and for case 2 and 3:对于案例 2 和案例 3:

const promise = (async () => Promise.resolve("A"))();

becomes:变成:

const promise = new Promise(resolve => {
         resolve(Promise.resolve("A"))
});

Putting all together and removing unnecessary functions and variable declarations:将所有内容放在一起并删除不必要的函数和变量声明:

// Promise A
new Promise(resolve => {
    // Promise B
    const b = new Promise<void>(resolve => {
        // Promise C
        new Promise(resolve => {
            resolve("A");
        })
        .then(function then1() {
            console.log("THEN");
            resolve();
        })
        .catch(function catch1() {
            console.log("CATCH");
        })
        .finally(function finally1() {
            console.log("FINALLY");
        });
    });
    resolve(b);
})
.then(function externalThen() {
    console.log("DONE");
});

For case 2 and 3 the Promise C declaration becomes:对于案例 2 和案例 3,Promise C 声明变为:

// Promise C
new Promise(resolve => {
    // Promise D
    resolve(Promise.resolve("A"));
})

How Promise code is executed Promise代码是如何执行的

  • the executor function passed to the Promise constructor is executed immediately.立即执行传递给 Promise 构造函数的执行程序 function。
  • the callbacks passed to then , catch and finally methods are executed as microtask when the promise fulffils.当 promise 满足时,传递给thencatchfinally方法的回调将作为微任务执行。
  • microtask are enqueue in a microtask queue微任务在微任务队列中排队
  • the microtask queue is emptied and all the tasks executed, in FIFO order, when the JS stack is empty当 JS 堆栈为空时,微任务队列被清空,所有任务按 FIFO 顺序执行
  • passing a Promise p1 to the resolve callback of a Promise p2 generates a new microtask that chains p1 to p2 .将 Promise p1传递给 Promise p2resolve回调会生成一个将p1链接到p2的新微任务。 The then method of p1 is called passing the resolve and reject callbacks of p2 .调用p1then方法传递p2resolvereject回调。

Execution case 1执行案例1

// Promise A
new Promise(resolve => {
    // Promise B
    const b = new Promise<void>(resolve => {
        // Promise C
        new Promise(resolve => {
            resolve("A");
        })
        .then(function then1() {
            console.log("THEN");
            resolve();
        })
        .catch(function catch1() {
            console.log("CATCH");
        })
        .finally(function finally1() {
            console.log("FINALLY");
        });
    });
    resolve(b);
})
.then(function externalThen() {
    console.log("DONE");
});
  1. execution traverse the Promise constructors for Promise A, B and C执行遍历 Promise 构造函数 Promise A, B 和 C
  2. C is resolved immediately C立即解决
  3. the execution of callback then1 is added in the microtask queue callback then1的执行被添加到微任务队列中
  4. execution continues chaining promises until resolve(b)执行继续链接承诺直到resolve(b)
  5. b is a Promise that is passed as resolve value for Promise A. This generates a new microtask that chains B to A. b是一个 Promise,作为 Promise A 的解析值传递。这会生成一个新的微任务,将 B 链接到 A。
  6. End of main block, two microtasks in the queue: then1 , chain-B-to-A .主块结束,队列中有两个微任务: then1chain-B-to-A
  7. execution of then1 : then1的执行:
    1. prints in console "THEN"在控制台打印“THEN”
    2. resolves Promise b解析 Promise b
    3. the Promise generated by then resolves and enqueues a microtask for catch1 then生成的 Promise 为catch1解析并入队一个微任务
  8. execution of chain-B-to-A : chain-B-to-A执行:
    1. in pseudo code: b.then(a.resolve, a.reject)在伪代码中: b.then(a.resolve, a.reject)
    2. the Promise B is already resolved therefore the microtask then-BA is enqueued Promise B 已经解析,因此微任务then-BA已入队
  9. microtask queue a this moment: catch , then-BA microtask queue a 这一刻: catch , then-BA
  10. execution of catch1 : catch1的执行:
    1. nothing to do with the callback与回调无关
    2. the Promise generated by catch resolves and enqueues a microtask for finally1 catch 生成的 Promise 解析并为finally1一个微任务
  11. execution of then-BA : then-BA的执行:
    1. Promise A resolves and enqueues a microtask for externalThen Promise A为externalThen解析并入队一个微任务
  12. microtask queue a this moment: finally1 , externalThen microtask queue a 这一刻: finally1 , externalThen
  13. execution of finally1 : prints "FINALLY" finally1的执行:打印“FINALLY”
  14. execution of externalThen : prints "DONE" externalThen的执行:打印“DONE”
  15. no more microtaks, code terminates没有更多的 microtaks,代码终止

Execution case 2执行案例2

// Promise A
new Promise(resolve => {
    // Promise B
    const b = new Promise<void>(resolve => {
        // Promise C
        new Promise(resolve => {
           // Promise D
           resolve(Promise.resolve("A"));
        })
        .then(function then1() {
            console.log("THEN");
            resolve();
        })
        .catch(function catch1() {
            console.log("CATCH");
        })
        .finally(function finally1() {
            console.log("FINALLY");
        });
    });
    resolve(b);
})
.then(function externalThen() {
    console.log("DONE");
});
  1. execution traverse the Promise constructors for Promise A, B and C执行遍历 Promise 构造函数 Promise A, B 和 C

  2. Promise C is resolved with Promise D, this generates a microtask to chain D to C Promise C 解析为 Promise D,这会生成一个微任务将 D 链接到 C

  3. execution continues chaining promises until resolve(b)执行继续链接承诺直到resolve(b)

  4. b is a Promise that is passed as resolve value for Promise A. This generates a new microtask that chains B to A. b是一个 Promise,作为 Promise A 的解析值传递。这会生成一个新的微任务,将 B 链接到 A。

  5. End of main block, two microtasks in the queue: chain-D-to-C , chain-B-to-A .主块结束,队列中有两个微任务: chain-D-to-Cchain-B-to-A

  6. execution of chain-D-to-C : chain-D-to-C执行:

    1. in pseudo code: d.then(c.resolve, c.reject)在伪代码中: d.then(c.resolve, c.reject)
    2. the microtask then1 is enqueued microtask then1入队
  7. execution of chain-B-to-A : chain-B-to-A执行:

    1. in pseudo code: b.then(a.resolve, a.reject)在伪代码中: b.then(a.resolve, a.reject)
    2. Promise B is not resolved, nothing else happens Promise B没有解决,没有其他事情发生
  8. microtask queue a this moment: then1 microtask queue a 这一刻: then1

  9. execution of then1 : then1的执行:

    1. prints in console "THEN"在控制台打印“THEN”
    2. resolves Promise b , this enqueues the then-BA microtask解析 Promise b ,这会将then-BA微任务排入队列
    3. the Promise generated by then resolves and enqueues a microtask for catch1 then生成的 Promise 为catch1解析并入队一个微任务
  10. microtask queue a this moment: then-BA , catch1 microtask queue a 这一刻: then-BA , catch1

  11. execution of then-BA : then-BA的执行:

    1. Promise A resolves and enqueues a microtask for externalThen Promise A为externalThen解析并入队一个微任务
  12. execution of catch1 : catch1的执行:

    1. nothing to do with the callback与回调无关
    2. the Promise generated by catch resolves and enqueues a microtask for finally1 catch 生成的 Promise 解析并为finally1一个微任务
  13. microtask queue a this moment: externalThen , finally1 microtask queue a 这一刻: externalThen , finally1

  14. execution of externalThen : prints "DONE" externalThen的执行:打印“DONE”

  15. execution of finally1 : prints "FINALLY" finally1的执行:打印“FINALLY”

  16. no more microtaks, code terminates没有更多的 microtaks,代码终止

Execution case 3执行案例3

// Promise A
new Promise(resolve => {
    // Promise B
    const b = new Promise<void>(resolve => {
        // Promise C
        new Promise(resolve => {
           // Promise D
           resolve(Promise.resolve("A"));
        })
        .then(function then1() {
            console.log("THEN");
            resolve();
        })
        .finally(function finally1() {
            console.log("FINALLY");
        });
    });
    resolve(b);
})
.then(function externalThen() {
    console.log("DONE");
});

All identical to case 2 until here:直到这里都与案例 2 相同:

  1. microtask queue a this moment: then1 microtask queue a 这一刻: then1
  2. execution of then1 : then1的执行:
    1. prints in console "THEN"在控制台打印“THEN”
    2. resolves Promise b , this enqueues the then-BA microtask解析 Promise b ,这会将then-BA微任务排入队列
    3. the Promise generated by then resolves and enqueues a microtask for finally1 then生成的 Promise 为finally1解析并入队一个微任务
  3. microtask queue a this moment: then-BA , finally1 microtask queue a 这一刻: then-BA , finally1
  4. execution of then-BA : then-BA的执行:
    1. Promise A resolves and enqueues a microtask for externalThen Promise A为externalThen解析并入队一个微任务
  5. execution of finally1 : prints "FINALLY" finally1的执行:打印“FINALLY”
  6. microtask queue a this moment: externalThen这一刻微任务队列: externalThen
  7. execution of externalThen : prints "DONE" externalThen的执行:打印“DONE”
  8. no more microtaks, code terminates没有更多的 microtaks,代码终止

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

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