【问题标题】:Find which promise failed in chain of .then查找 .then 链中哪个承诺失败
【发布时间】:2020-11-29 08:15:23
【问题描述】:

我正在尝试在我的 node + express 应用程序中设计一个带有 catch 错误的承诺链。在下面的示例中,如果任何一个“then”函数出错,我将不得不向后工作以从错误消息中找到哪一个。有没有更简单的方法来编写 catch 函数?

    new Promise(function(resolve, reject) {
       resolve(groupId);
    })
    .then(sid => getGuestGroup2(sid))matching carts
    .then(group =>getProducts(group))//add products
    .then(result2 =>getPrices(result2))
     .catch(error => { // (**)
        console.log('Error on GET cart.js: '+error);
        res.sendStatus(500);
      });

【问题讨论】:

  • 错误堆栈包含行号。这应该可以准确地告诉您链条的哪一部分失败了。此外,您对 promise 构造函数的滥用可以简化为 Promise.resolve(groupId)
  • 如果您想要不同的错误处理,也可以散布捕获和然后。换句话说,如果你真的想抓住所有东西,把 catch 放在最后是很方便的,但它通常不太理想。
  • "找到哪一个" - 你为什么关心这个?错误(消息)应该包含所有相关细节,我看不出使用它有什么问题。
  • 仅供参考,在您显示的代码中,.then(sid => getGuestGroup2(sid))matching carts 是一个语法错误。
  • 要查看完整错误,您需要将console.log('Error on GET cart.js: '+error); 更改为console.log('Error on GET cart.js: ', error);

标签: javascript node.js express promise es6-promise


【解决方案1】:

Promise 链接足够通用,不包含开箱即用的“哪个步骤失败”类型的信息。您可能会尝试从堆栈跟踪中对其进行解码,但在我看来,这比它的价值要多得多。您可以使用以下几个选项来确定哪个步骤失败。

选项 1

在错误对象上设置一个额外的属性(作为指示符),可以在 catch 块中对其进行解码以确定错误源自链中的哪个步骤。

function predictibleErrors(promise, errorCode) {
    return Promise.resolve(promise)
        .catch(err => {
            const newErr = new Error(err.message);
            newErr.origErr = err;
            newErr.errorCode = errorCode;
            throw newErr;
        });
}

Promise.resolve(groupId)
    .then(sid => predictibleErrors(getGuestGroup2(sid), 'STEP_1')) // matching carts
    .then(group => predictibleErrors(getProducts(group), 'STEP_2')) // add products
    .then(result2 => predictibleErrors(getPrices(result2), 'STEP_3'))
     .catch(error => { // (**)
        console.log('Error on GET cart.js: '+error);

        // Check error.errorCode here to know which step failed.

        res.sendStatus(500);
      });

选项 2

Good old,每一步都捕获,然后重新抛出以跳过后续步骤。

Promise.resolve(groupId)
    .then(sid => getGuestGroup2(sid)) // matching carts
    .catch(err => {
        console.log('step 1 failed');
        err.handled = true; // Assuming err wasn't a primitive type.
        throw err;
    })
    .then(group => getProducts(group)) // add products
    .catch(err => {
        if(err.handled) { return; }
        console.log('step 2 failed');
        err.handled = true;
        throw err;
    })
    .then(result2 => getPrices(result2))
    .catch(err => {
        if(err.handled) { return; }
        console.log('step 3 failed');
        err.handled = true;
        throw err;
    })
    .catch(error => {
        // Some step has failed before. We don't know about it here,
        // but requisite processing for each failure could have been done
        // in one of the previous catch blocks.
 
        console.log('Error on GET cart.js: '+error);
        res.sendStatus(500);
    });

请注意,我们在选项二中所做的事情,也可以直接由底层方法完成。例如。 getGuestGroup2getProducts 可以在它抛出的错误对象上包含 errorCode 或类似属性。在这个例子中,我们知道第 1 步或第 2 步失败,但不知道为什么。如果底层方法设置相同,它们可以包含更准确的错误代码,并知道操作失败的原因。我没有采取那条路线,因为这些方法未包含在您的示例中,而且据我所知,它们可能不在您的控制范围内。

【讨论】:

  • 选项 2 不起作用。如果getGuestGroup2 拒绝,它将记录它失败的每个步骤。嵌套是不可避免的。
  • Btw 在选项 1 中你忘了throw newErr
  • @Bergi,感谢您指出选项 1 中的缺失。我已更新。失败的行为将是第二种方法的副作用。如果需要,可以通过合并第一个选项的某些方面来避免这种情况。我添加了一个这样的选项。
猜你喜欢
  • 1970-01-01
  • 2021-10-17
  • 1970-01-01
  • 2019-08-16
  • 2019-09-08
  • 1970-01-01
  • 2015-08-15
  • 2018-03-18
  • 2019-02-18
相关资源
最近更新 更多