Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't Promise catch error thrown by async operation? [duplicate]

Given the the following code:

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);
  });

I would expect that the fileError that is thrown (because the file I try to load does not exist) will be caught by the Promise and funneled into the .catch() statement. So in the end I'd have this output: error received: ENOENT.

However, when I run this code I get the following instead:

    if (err) throw err;
             ^

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

So the error was not caught: it threw just as it normally would, as though it were outside a Promise.

Why is this happening?

Everything I can find to read about Promises is more concerned with errors being silently swallowed than with this problem, where it actually throws when you don't want it to!

And how should I achieve my intent here? Do I need to use try-catch statements and the reject handler?

like image 410
davidtheclark Avatar asked Nov 11 '15 13:11

davidtheclark


People also ask

Can we use async with promises?

async and awaitInside an async function, you can use the await keyword before a call to a function that returns a promise. This makes the code wait at that point until the promise is settled, at which point the fulfilled value of the promise is treated as a return value, or the rejected value is thrown.

Are promises executed asynchronously?

A promise is used to handle the asynchronous result of an operation. JavaScript is designed to not wait for an asynchronous block of code to completely execute before other synchronous parts of the code can run. With Promises, we can defer the execution of a code block until an async request is completed.

What happens when a promise throws an error?

The Promise returned by catch() is rejected if onRejected throws an error or returns a Promise which is itself rejected; otherwise, it is fulfilled.


1 Answers

You cannot catch an error thrown in an asynchronous callback function using promises, since its context will be lost. In your case with Node, you will loose the context of the error in the process.on('uncaughtException') handler, and the callback will run as its own event in the eventqueue, with its own context and scope.

Using promises, the correct solution will be to reject the wrapping promise.

An alternative would be to use a Domain object (Domain documentation), but it's pending deprecation. With a domain you can maintain the context and register a handler for your errors, as below.

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
});
like image 127
Daniel B Avatar answered Oct 04 '22 02:10

Daniel B