Promise.all遭到未处理的拒绝

时间:2019-05-28 06:36:31

标签: node.js ecmascript-6 promise es6-promise bluebird

我正在使用Promise.all并捕获错误,但仍收到未处理的拒绝

const Promise = require('bluebird');

function sleep(milis) {
return new Promise(function(resolve, reject) {
    if (milis == 1000) {
        console.log('Rejecting millis', milis)
        setTimeout(() => {
            reject('Got error')
        }, milis);

    } else {
        console.log('Processing millis', milis)
        setTimeout(() => {
            resolve(milis);
        }, milis);

    }
});
}

function test() {

try {
    let lists = [2000, 1000, 3000]
    Promise.all(
            lists.map(record => {
                try {
                    sleep(record)
                } catch (err) {
                    console.log('Error inside catch block1', err)
                    throw err
                }
            })
        ).then(data => {
            console.log('Resolved', data)
        })
        .catch(err => {
            console.log('Error inside catch block2', err)
            throw err

        });

} catch (err) {
    console.log('Error inside catch block3', err)
}
}


test();

使用catch块后,为什么仍会出现Unhandled拒绝。任何帮助表示赞赏。但是,如果我使用异步等待,则不会收到未处理的拒绝。

3 个答案:

答案 0 :(得分:1)

TL; DR:throw err处理程序中的.catch不会被代码中的其他catch捕获,因此您会遇到未处理的承诺拒绝。

首先,在此代码段中

lists.map(record => {
  try {
    sleep(record)
  } catch (err) {
    console.log('Error inside catch block1', err)
    throw err
  }
})

.map的结果将是[undefined, undefined, undefined],因为该函数不返回任何值。如果希望它返回每个列表元素的承诺,则需要编写return sleep(record)

然后,请注意,主catch块是在.then的{​​{1}} / .catch处理程序之前执行的。如果在主要Promise.all主块之后添加console.log ,则会看到它。这意味着您在catch处理程序中重新抛出的异常不会被任何东西捕获,并显示为未处理。

答案 1 :(得分:1)

原因是您没有在此sleep方法上处理错误。 看起来应该像这样。

function sleep(milis) {
return new Promise(function (resolve, reject) {
    if (milis == 1000) {
        console.log('Rejecting millis', milis)
        setTimeout(() => {
            reject('Got error')
        }, milis);

    } else {
        console.log('Processing millis', milis)
        setTimeout(() => {
            resolve(milis);
        }, milis);

    }
 }).catch(error => {
    console.log(error);
 })
}

答案 2 :(得分:1)

您的代码有多个问题,让我们一步一步地解决它们:

首先

在映射lists数组时,您永远不会返回从sleep()函数获得的承诺。这意味着您提供给Promise.all()的是一个由undefined填充的数组。 Promise.all()将非承诺的值视为已解决的承诺,因此,无论Promise.all()创建的承诺是解决还是拒绝,您的sleep()都会始终解析。这也意味着没有任何东西能够捕捉到sleep()拒绝的诺言,这就是为什么您的脚本当前无法处理诺言的原因。 您可以通过使用return sleep(record)正确返回承诺来解决此问题。但这还不足以消除所有未处理的诺言拒绝,因此让我们继续...

第二

您已将对sleep()的呼叫包装在try-catch块中。除非您使用async-await,否则try-catch阻止将捕获被拒绝的承诺。在这种情况下,它将仅捕获创建诺言时引发的错误。如果这是您的意图,那很好,但是如果您的意图是兑现被拒绝的承诺,那将是行不通的。

第三次

您已将catch()处理程序附加到Promise.all()。与前面提到的try-catch不同,实际上它处理了所有被拒绝的承诺。但是,您在该处理程序中重新抛出了错误,这意味着承诺链仍将被拒绝。您已经将Promise.all()包裹在另一个try-catch块中,但是如上所述,这不能捕获已拒绝的承诺,因此仍然被拒绝的承诺最终将无法得到处理。
在这种情况下,您不应简单地在最后一个catch()处理程序中重新抛出错误,因为我在这里看不到这样做的任何意义。如果出于任何原因需要重新抛出它,则需要在链的后面添加另一个catch()处理程序。