【问题标题】:Why is the error not being caught in this NodeJS async function?为什么这个 NodeJS 异步函数中没有捕获到错误?
【发布时间】:2018-12-11 18:25:51
【问题描述】:

我试图理解为什么上传函数中的 catch 块没有捕获 createReleaseVersion 函数中 request(.....) 行之后抛出的异常。 nodejs 脚本崩溃,异常未处理。控制台只显示异常的错误。

在下面的代码中,我希望先打印“得到你”,然后打印“之后”,但它没有发生。

如果我将 throw 替换为 return reject (...同一个对象),那么我会得到所需的输出。
我先打印“得到你”,然后打印“之后”

function createReleaseVersion(releaseVersion) {
    var options = {
        uri: 'https://someurl',
        method: 'POST',
        json: {'version': releaseVersion}
    };

    return new Promise(function(resolve, reject) {
        request(options, function (error, response, body) {
            throw {
                error: error,
                response: response,
                body: body
            };
            console.log(body);
            if (error) {
                throw {
                    error: error,
                    response: response,
                    body: body
                };
            } else {
                resolve();
            }
        });
    });
}

async function upload(releaseVersion) {
    try {
        await createReleaseVersion(releaseVersion);
    } catch (error) {
        console.log('got you');
    }
    console.log('after');
}

upload('ddd');

【问题讨论】:

标签: node.js error-handling promise async-await


【解决方案1】:

好吧,让我们举一个更简单的例子:

new Promise((resolve, reject) => {
  setTimeout(() => { throw new Error(); });
});

这会使进程崩溃。原因是 setTimeout(或 request 在您的情况下)订阅了稍后调用的回调

当回调最终被调用时——promise 构造函数已经执行完毕并且错误被抛出到当前上下文(setTimeout/request's)。

promise 构造函数同步捕获错误的原因是它基本上是这样做的:

try {
   executor(resolve, reject); // your code
} catch (e) {
   reject(e);
}

因为在您的情况下,该函数不会同步执行 - 它无法了解异常的上下文。这在未来可能会随着 Zones 而改变,但可能不会。

如果您想在承诺函数中标记错误 - 您可以调用第二个参数 (reject) 和 reject(new Error(...))

我强烈建议您使用 util.promisify 而不是手动将 API 转换为 Promise 以避免此类问题 :)

我还建议您只拒绝 Error 对象以获得更好的堆栈跟踪。

【讨论】:

  • 感谢您的出色回答。关于你写的另一个问题'如果你想在一个承诺的函数中标记一个错误 - 你可以调用第二个参数(reject)和reject(new Error(...))'。您能否提供更多详细信息,我该如何采用这种方法。您的意思是将请求调用包装在 resolve 中?
  • 当然:new Promise((resolve, reject) => setTimeout(() => reject(new Error())) 将创建一个 rejected 承诺 - 这不是 throw new Error 在那里不起作用。
猜你喜欢
  • 2021-01-15
  • 1970-01-01
  • 2011-04-12
  • 2021-10-20
  • 2019-01-31
  • 2022-01-08
  • 2019-11-01
  • 2012-01-01
  • 2022-12-10
相关资源
最近更新 更多