异步函数在等待嵌套的Promise实现时永远不会返回

时间:2017-10-24 07:25:31

标签: javascript node.js asynchronous promise async-await

在下面的代码中,有一个outer函数和一个inner函数。 outer应该await inner,并在完成后返回。 inner返回Promise,超时后即可完成。我希望在outer完成后立即返回Promise函数:

const outer = async () => {
    let counter = 0;
    const inner = async () => {
        console.log('inner');
        return new Promise((fulfill, reject) => {
            if (++counter === 3) {
                console.log('fulfill');
                fulfill();
                return;
            }
            setTimeout(() => inner(), 1000);
        });
    };
    return await inner();
};
outer().then(() => console.log('outer done'));

outer永远不会完成。请注意,没有outer done输出:

inner
inner
inner
fulfill

在以下代码中outer完成。它返回Promise本身,inner函数实现它:

const outer = async () => {
    return new Promise((fulfill, reject) => {
        let counter = 0;
        const inner = async () => {
            console.log('inner');
            if (++counter === 3) {
                console.log('fulfill');
                fulfill();
                return;
            }
            setTimeout(() => inner(), 1000);
        };
        inner().catch(err => reject(err));
    });
};
outer().then(() => console.log('outer done'));

输出:

inner
inner
inner
fulfill
outer done

我认为在这两种情况下行为都应该相似。任何人都可以看到并解释其中的差异吗?

1 个答案:

答案 0 :(得分:4)

您从未在fullfill中调用inner函数。你创造了一堆新的Promises,你只告诉了它已经解决的最后一个承诺。

让我们来看看您的异步任务:

{
    if (++counter === 3) {
        console.log('fulfill');
        fulfill();
        return;
    }
    setTimeout(() => inner(), 1000);
}

在第一次调用inner时,即此部分:

return await inner();

counter为0.这意味着不会执行整个if块。在其余代码中,它从未调用fulfill函数,因此承诺永远不会得到解决。

如果您的生产代码库中存在此代码(或此样式的代码),我的建议是您应该重写它。

要快速修复 ,您可以这样做:

setTimeout(() => inner().then(() => fulfill()), 1000);

Demo