【问题标题】:Throwing inside a catch block in a nested Promise to trigger the catch block of outer Promise, is there an alternative cleaner way?在嵌套的 Promise 中的 catch 块内抛出来触发外部 Promise 的 catch 块,是否有另一种更清洁的方法?
【发布时间】:2019-05-08 06:25:22
【问题描述】:

我正在嵌套 Promise,我必须知道嵌套的 Promise 是被拒绝的 Promise 还是已完成的 Promise 才能知道是否触发外部 Promise 链的捕获。为了区分嵌套的 Promise 是否被拒绝或履行,我在嵌套的 Promise 的 catch 中使用 throw 来表示拒绝;而当我的嵌套 Promise 的 catch 中没有 throw 时,总是会指示实现。请看下面的例子:

let test = new Promise((resolve, reject) => {
  resolve(42);
}).then((e) => {
  console.log(e);
  return new Promise((resolve, reject) => { //Error happens inside this nested Promise
    resolve(32);
  }).then((e) => {
    console.log(e);
    //Run other processes that may lead to an error
  }).catch((e) => { //I added this catch block for error detection, whatever error it might be
    console.log(e);
    throw(e); //I'm throwing (e) from the inner Promise's catch so that the returned Promise in the outer then is a rejected Promise, which will be "caught" by the catch block of the outer Promise
  });
}).catch((e) => {
  console.log(e); //I handle error that happen may either in the inner Promise or the outer Promise here
});

上面显示了我在嵌套 Promise 的 catch 块中所说的 throw-ing 的意思。以上是指示嵌套 Promise 失败的标准方法,还是有另一种更清洁的方法来实现我想要的?如您所见,我实际上在嵌套的 Promise 中使用了两次 throw-ing 来表示拒绝。有没有办法让我可以throw 一次并表示 Promise 拒绝?

编辑

我在我的内部 Promise 中使用 catch 块的原因我的外部 Promise:我想检测我的内部 Promise 中的错误,并且说检测是使用我的内部 @987654331 完成的@ 堵塞;我想使用相同的处理程序处理内部 Promise 或外部 Promise 中可能发生的错误,这是使用我的外部 catch 块完成的。因为catch-ing 在我的内部 Promise returns 中是一个 Promise,它被认为已满足我的外部 Promise 的 then 块,所以我决定在我的内部 catch 块中使用 throw 来表明它实际上 如果到达内部 catch 块,则不满足。我还编辑了我的代码,表明我的内部 Promise 中发生的错误不是由我在代码中throw-ing 手动触发的

【问题讨论】:

  • 为什么在嵌套的 promise 中使用 catch/throw 块?这是多余的。如果您不希望您的内部承诺被拒绝或让您的顶级承诺完成工作,请使用 catch
  • @AndreiBelokopytov 并非总是如此,但在任何级别的一个地方处理错误是一个很好的设计。这取决于场景。想象一下,您想记录错误,更改该特定错误的某些状态 - 最好将它放在一个地方(想象嵌套的 Promise 作为其他模块的函数使用)。
  • @tomericco 谢谢。那么在您看来,在任何级别的一个地方处理错误并通过在我的内部 Promise catch 块中使用 throw 来指示嵌套的 Promise 被拒绝是一种好习惯吗?
  • @tomericco 我同意你关于错误处理的观点,但你的例子恰恰相反。你在内部promise中处理了错误,为什么需要抛出它?如果你想处理外部代码中的错误,那么你不需要在内部 Promise 中使用 catch 块。
  • 你应该使用 return Promise.reject(new Error('error')) 而不是 throw('error')。如果你使用 Promise,你应该使用 Promise 函数,因为它们完全是为 Promises 制作的,没有意外的交互。

标签: javascript promise es6-promise


【解决方案1】:

我认为执行此操作的简洁方法是使用 async/await。但是在去那里之前,你的问题是当内部承诺失败时如何不运行外部承诺?

下面的例子:

  • 当内部承诺拒绝时,链停止。
  • 当外部承诺拒绝时,内部承诺已经实现。

const fun42 = () => {
    return new Promise((resolve, reject) => {
        setTimeout(() =>{
            resolve(42)
            reject('something at fun 42 went wrong')
        }, 500)
    })
}

const fun32 = () => {
    return new Promise((resolve, reject) => {
        setTimeout(() =>{
            //resolve(32)
            reject('something at fun 32 went wrong')
        }, 500)
    })
}

fun32().then(x => {
    console.log(x)
    return fun42()
}).then( y => {
    console.log(y)
}).catch (e => {
    console.log(e)
})

【讨论】:

  • 对于您的问题:是的,当内部 Promise 被拒绝时,我不想在外部 Promise 中运行 thens,因此只能立即转到 catch 块。但是,从我读过的评论和你给出的例子来看,似乎我在我的内部 Promise 中添加 catch 块时犯了一个错误。
【解决方案2】:

嗯,这是一个设计问题。错误处理应该发生在每个级别的一个地方(就像您在示例中所做的那样)。嵌套的 catch 函数处理错误,决定它是应该传播它还是安静地完成它(就像你写的那样)。

在该特定示例中,我将使用包装 Promise 的 reject 函数来拒绝它,而不是抛出错误。

【讨论】:

  • 我认为我错过了一点:如何在不使用 catch 的情况下检测到我的内部 Promise 内部发生的错误?我使用catch 的原因是为了知道我内心的 Promise 内部发生了一些错误。请注意,我上面的示例总是以throw 结尾。在我正在处理的真实代码中,Promise 可以被实现或被拒绝。为了检测由于错误而导致的拒绝,我使用catch 来检测所述错误,并使用throw 来“告诉”外部 Promise 在我的内部 Promise 内部发生了错误,以跳过我的下一个 thens外部承诺。
  • 我不同意,错误处理应该在每个级别发生一次。 .catch 返回一个 Promise 是一个很大的好处,因此您可以为 Promise 链中的每个 .then 添加一个 .catch,并且可以通过它自己的 .catch 处理每个 .then 的错误,而不是处理链中所有 .then 的所有错误只有一点。
  • @RichardW:如果您想在不使用 catch 的情况下捕获错误,您必须知道您期望的错误类型。假设你会做 (a / b),那么 b 不能为零。添加到您的代码if (b === 0) return console.log('cannot divide by zero')。这也将结束链条。
  • @Edwin 可能会发生所有不同类型的错误,我不想逐一指定(因为有很多),因此使用catch。我认为在不知道发生哪种类型的错误并且不使用 catch 的情况下检测错误是不可能的,那么?作为参考,这里是我正在谈论的错误列表:firebase.google.com/docs/storage/web/handle-errors
  • 参考中列出的错误将冒泡到链末端的捕获。如果错误发生在链中的第 n 步。 n 之后的所有步骤都不会被执行,catch 将返回。 n 之前的所有步骤都已解决。
猜你喜欢
  • 2017-09-30
  • 1970-01-01
  • 2021-03-03
  • 2017-05-11
  • 1970-01-01
  • 2017-06-20
  • 2017-07-27
  • 2017-04-03
相关资源
最近更新 更多