简体   繁体   中英

How to handle asynchronous error in Node.js

Is there any alternative to Bluebird's Promise.try function? As I'm using async/await not interested in adding bluebird dependency.

Is there a better way to capture asynchronous error in Node.JS

await Promise.try(async function() {
    // Some code with async operations like readline
    await this.nextCall(batchData, true);
}).catch(async function(err) {
    // My error handling
});

Any inbuilt functions in Node.js 10.x?

UPDATE :

Is there a better way to capture asynchronous error in Node.JS

try {
    let interfaceVal = lineReader.createInterface({
        input: fs.createReadStream(filePath)
    });
    interfaceVal.on('line', async (line) => {
        throw new Error('My custom Error');
    });
    // some sync operations
} catch(e) {
    // This catch won't get called with custom error
    console.log(e);
}

Any idea to capture such asynchronous errors?

In nodeJs, if you're using async/await you can use plain try catch blocks and it will catch your errors (and it will work for async calls)

try {
   await this.nextCall(batchData, true);
}
catch(exc) {
 // handle error
}

this function definition needs to be declared as async

There is no reason to wrap async function with Promise.try . The purpose of Promise.try is to handle both synchronous errors and rejections similarly:

Start the chain of promises with Promise.try. Any synchronous exceptions will be turned into rejections on the returned promise.

This is already done with async since it always returns a promise.

This can be used at top level with async IIFE:

(async function() {
    await this.nextCall(batchData, true);
})().catch(console.error);

Or in case async is nested it can be omitted, a rejection can be handled in parent async function with try..catch , as another answer explains.


In this case an error can be caught only inside async function:

    interfaceVal.on('line', async (line) => {
      try {
        throw new Error('My custom Error');
      } catch (err) {
        console.error(err);
      }
    });

The use of non-promise API (Node stream) doesn't allow for error handling with promises. Stream callback ignores rejected promises and doesn't allow to propagate the error outside the stream.

Callbacks can be converted to promises only when they are expected to be called once . This is not the case with line . In this case asynchronous iterator can be used, this one of its use cases .

Event emitter can be converted to async iterator with p-event and iterated with for await of inside async function:

try {
    let interfaceVal = lineReader.createInterface({
        input: fs.createReadStream(filePath)
    });

    const asyncIterator = pEvent.iterator(interfaceVal, 'line', {
      resolutionEvents: ['close']
    });

    for await (const event of asyncIterator) {
        console.log('line', event);
        // throw new Error('My custom Error');
    }
} catch(e) {
    console.log(e);
}

Promise.try is on its way for specification . Here is the polyfill :

if (typeof Promise !== 'function') {
    throw new TypeError('A global Promise is required');
}

if (typeof Promise.try !== 'function') {
    Promise.try = {
        try(func) {
            if (typeof this !== 'function') {
                throw new TypeError('Receiver must be a constructor');
            }
            return new this(function (resolve) {
                resolve(func());
            });
        }
    }.try;
}

This polyfill supports promise subclassing and other features. This is safe to polyfill in Node.js.

You don't need to specify a catch clause explicitely in an async function, because it uses the natural Error semantics. Here your function operation_A throws an error, because operation_B rejected.

 const operation_B = () => { return new Promise((resolve,reject) => { window.setTimeout(() => { //resolve("RESOLVE: all your base are belong to us"); reject("REJECT: all your base are belong to us"); },2000); }); }; const operation_A = async () => { const B = await operation_B(); return B.toUpperCase(); }; operation_A().then(console.log).catch(console.error); 

If you do not want any third-party package you can handle errors on your own.

First write a middleware:

// you could add more logic and create a middleware function
// this should be registered after route handlers
app.use((error, req, res, next) => {
  console.log("error",error)
  console.log('Path: ', req.path)
  next() 
})

write a wrapper function:

const catchAsyncErrors = (func) => (req, res, next) =>
  // passing a controller function for func
  Promise.resolve(func(req, res, next)).catch((err) => {
    // If resolving results in error, our error handler will catch it
    next();
  });

export default catchAsyncErrors;

Wrap your controllers with catchAsyncError

const registerUser = catchAsyncErrors(async (req, res) => {
      .....
      }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM