为什么 Promise 不捕获异步操作引发的错误?

dav*_*ark 6 javascript error-handling promise es6-promise

鉴于以下代码:

var fs = require('fs');

var asyncErrorPromise = new Promise(function(resolve) {
  fs.readFile('does/not/exist.blah', function(fileError, content) {
    if (fileError) throw fileError;
    resolve(content);
  });
});

asyncErrorPromise
  .then(function(content) {
    console.log('content received: ' + content);
  })
  .catch(function(err) {
    console.log('error received: ' + err.name);
  });
Run Code Online (Sandbox Code Playgroud)

我希望fileError抛出的那个(因为我尝试加载的文件不存在)将被 Promise 捕获并汇集到.catch()语句中。所以,最后我不得不这样的输出:error received: ENOENT

但是,当我运行此代码时,我得到以下信息:

    if (err) throw err;
             ^

Error: ENOENT: no such file or directory, open 'does/not/exist.blah'
    at Error (native)
Run Code Online (Sandbox Code Playgroud)

所以错误没有被捕获:它像往常一样抛出,好像它在 Promise 之外。

为什么会这样?

我能找到的关于 Promises 的所有内容都更关心错误被默默吞下,而不是这个问题,当你不想要它时它实际上会抛出!

应该如何在这里实现我的意图?我需要使用 try-catch 语句和reject处理程序吗?

Dan*_*l B 4

您无法使用 Promise 捕获异步回调函数中抛出的错误,因为它的上下文将会丢失。在使用 Node 的情况下,您将失去处理程序中错误的上下文process.on('uncaughtException'),回调将作为事件队列中自己的事件运行,具有自己的上下文和范围。

使用承诺,正确的解决方案是reject包装承诺。

另一种方法是使用Domain对象(域文档),但它正在等待弃用。使用 a,domain您可以维护上下文并为错误注册处理程序,如下所示。

var domain = require('domain');

var d = domain.create();

d.on('error', function(err){
    //Do something with your error
});

d.run(function(){
    //Run your async code that might throw error
});
Run Code Online (Sandbox Code Playgroud)