理解带有 catch 和 then 的 Promise 链

问题描述 投票:0回答:2

我无法理解以下承诺链的结果

function job(state) {
    return new Promise(function(resolve, reject) {
        if (state) {
            resolve('success');
        } else {
            reject('error');
        }
    });
}

let promise = job(true);

promise

.then(function(data) {              ///1
    console.log(data);

    return job(true);
})

.then(function(data) {              ///2
    if (data !== 'victory') {
        throw 'Defeat';
    }

    return job(true);
})

.then(function(data) {              ///3
    console.log(data);
})

.catch(function(error) {              ///4
    console.log(error);

    return job(false);
})

.then(function(data) {              ///5
    console.log(data);

    return job(true);
})

.catch(function(error) {              ///6
    console.log(error);

    return 'Error caught';
})

.then(function(data) {              ///7
    console.log(data);

    return new Error('test');
})

.then(function(data) {              ///8
    console.log('Success:', data.message);
})

.catch(function(data) {              ///9
    console.log('Error:', data.message);
});

输出是

成功 打败 错误 发现错误 成功:测试

我明白为什么会打印“成功”和“失败”。 但后来我很困惑。为什么跳过3,4,5而执行6? 那么既然7抛出了错误,难道不应该执行9而不是8吗?

javascript promise
2个回答
0
投票

让我们用您在注释旁边添加的数字来调用

then
catch
方法返回的承诺。请注意,这些
then
catch
方法是同步执行的,因此我们立即有一堆 Promise,并且它们一开始都是待处理的。唯一立即满足的是
promise
(它没有得到数字,所以我们给它数字 0)。

现在让我们一步步来看:

Promise 0 (

promise
) 被分配了一个具有“成功”价值的 Promise。

回调 1 执行,因为承诺 0 已履行,所以我们得到输出“成功”。此回调返回一个新的承诺,该承诺也满足值“成功”。 Promise 1 复制了该 Promise 的状态,因此它“成功”地实现了。

回调 2 也会执行,因为承诺 1 已实现。您不会在回调编号 2 中打印任何内容,但如果您愿意,它也会被输出。

if
条件为 true,因此回调 2 会抛出错误“Defeat”。这使得 Promise 2 以“失败”为理由拒绝。

为什么跳过3,4,5

第三个回调被跳过,因为该回调仅应在 Promise 2 满足时执行。但由于它被拒绝,并且您没有为其提供 catch 回调(

then
的第二个参数不存在),promise 3 只是复制了promise 2 的状态。所以现在promise 3 也被拒绝了。

回调编号4不被跳过;它执行了!第 3 号 Promise 被拒绝,并在那里打印“Defeat”。然后,此回调继续返回一个被拒绝的 Promise (

job(false)
),其原因为“错误”(参见
job
),因此 Promise 4 也会以相同的原因拒绝。

回调 5 仅应在 Promise 4 满足时执行,但当 Promise 4 被拒绝时,它不会执行。当 Promise 4 拒绝时,这里也没有回调要执行,因此 Promise 5 只是复制 Promise 4 的状态并以“错误”为理由拒绝。

它执行了6?

回调 6 执行,因为它应该在 Promise 5 拒绝时执行——它确实这么做了——所以我们得到一个输出“错误”。此回调返回一个字符串“Error catched”,该字符串将成为 Promise 6 履行的值。

回调 7 执行,因为它应该在 Promise 6 满足时执行——它确实做到了——所以我们得到一个输出“错误捕获”。回调 7 返回一个带有消息“test”的

Error
对象。 Promise 7 以此 Error 对象作为值来实现。

那么既然7抛出了错误,是不是应该执行9而不是8呢?

这是一个误会。回调 7 not 不会抛出错误。它返回一个对象,该对象恰好是

Error
的实例,但这无关紧要。如果
then
回调返回的值不是 Promise 对象(或另一个“thenable”),那么该值将是相应 Promise 所实现的值。
Error
对象也不例外。

所以回调 8 会执行,因为它应该在 Promise 7 满足时执行——它确实做到了——所以我们得到一个输出“错误捕获”。这里没有返回任何内容,这意味着 Promise 8 满足了值

undefined

回调 9 不执行,因为它应该在 Promise 8 拒绝时执行,但它实现了。由于 Promise 8 履行时没有处理程序,因此 Promise 9 仅复制 Promise 8 的状态。由于 Promise 9 没有附加回调,因此不会执行任何其他操作。

我希望这能澄清这一点。


0
投票

虽然 trincot 的解释非常详细,但帮助我理解承诺链的是将其可视化。

这是您的代码示例中发生的情况:

  • 每一个承诺都有成功或失败
  • 虚线路径代表失败
  • 坚实的道路代表成功
  • 彩色路径代表代码示例执行

值得一提的是:

  • 如果虚线路径没有被catch处理,它会生成一个
    unhandled promise exception
    ,导致nodejs进程崩溃
  • 如果一个promise返回一个promise(或一个promise链),它会被插入到正在创建的有向图中

© www.soinside.com 2019 - 2024. All rights reserved.