4

I'm using async waterfall. When one of my functions calls callback(err), my custom async callback is called. Inside of there I throw an error, hoping it will be caught in the try block around async, but that's not happening.

try {
    async.waterfall([function1, function2], myAsyncCallback);
}
catch(err) {
    console.log("THIS CODE IS NEVER EXECUTED.");
}

var function1 = function() {
...
   //some error occurs:
   callback(new Error(errMsg), errMsg);
...
}

var function2 = function() {
...
}

function myAsyncCallback(err, result) {
    console.log("This code gets executed.");
    if (err) {
            console.log("This code gets executed too.");
            throw new Error("I want this error caught at the top around the catch around async.waterfall()");
        }
}
3
  • This is where code formatting matters: right now you declare myAsyncCallback inside of your function1, so this is not really sensible code. Can you please reduce this to a minimal reproducible example that people can copy-paste to a file and run in node to see the same thing you see, instead of posting code that is guaranteed to not show your problem because it can't run? Commented Nov 17, 2016 at 18:02
  • @Mike, they actually aren't inside of each other. Updated the sample, so hopefully that makes it clear. You should be able to remove "..."s to test it out. Commented Nov 17, 2016 at 18:07
  • I added an answer, but might need more insight into the functions being called. I posted my working code, which looks a lot like your example! Commented Nov 17, 2016 at 18:16

3 Answers 3

3

https://runkit.com/imjosh/async-try-catch/2.0.0

var async = require('async');

try {
  async.waterfall([function1, function2], myAsyncCallback);
}
catch(err) {
  errorHandler(err);
}

function function1(callback) {
  console.log('in fn1')   
  callback(null,'fn1');   
}

function function2(fn1, callback) {
  console.log('in fn2')
  callback(null, fn1 + 'fn2');
}

function myAsyncCallback(err, result) {
    if (err) {
      console.error('There was an error: ' + err);
      return;
    }
    //an error occurs. this gets caught by the outer try block
    //var foo = outer; //oops, outer is not defined. This throws an error

    //same scenario but inside an async function
    //can't/won't be caught by the outer try block
    setTimeout(function(){ 
        try{ //need try here
          var foo = inner; //oops, inner is not defined. This throws an error
        } 
        catch(err) {
          errorHandler(err);
       }
    }, 1000);

    console.log('Result was: ' + result);
}

function errorHandler(err){ 
  //Make error handler a function that can be called from either catch
  console.log('caught error: ' + err);
}
Sign up to request clarification or add additional context in comments.

2 Comments

the error occurs in the async module callback, what I called myAsyncCallback. Errors inside of the function1 do get caught in the first try/catch block, but that's not what I'm trying to do.
I've edited the answer. All of the error handling is in one place. Exceptions inside myAsyncCallback get handled. It's very difficult to see what you're trying to do w/o seeing your actual code.
1

hoping it will be caught in the try block around async, but that's not happening

That's impossible. The error will be created and thrown asynchronously, i.e. long after the async.waterfall has returned and the try block was left. If you want to handle an asynchronous errors, do it in myAsyncCallback (just like you already do). Never throw in an asynchronous callback.

3 Comments

This is not accurate. The scope created when async.waterfall is called will remain until the chain dies. Thrown errors will "bubble up" back through a call chain. I would agree that throwing in an asynchronous callback is problematic (because it's such a pain to trace the error), but is is not impossible. Could you edit this answer?
@clay Which scope are you talking about? There are no closures in the OPs code, so the scope is destroyed when it is left. Or what do you mean by "until the chain dies"? Notice that the myAsyncCallback which throws in the OPs code is not called by async.waterfall - it's asynchronous.
I guess I meant the callback chain. But you are correct, there is different behavior if the callback is called asynchronously or not. I have some studying to do, I guess! Thanks for your answer.
-1

Works for me. Do you see any differences? I will update my answer if something more comes to light.

This is my output:

[Clays-MacBook-Pro ~/Documents/workspace/scratch]:node index.js 
inside function1
This code gets executed.
This code gets executed too.
THIS CODE IS NEVER EXECUTED.
[Clays-MacBook-Pro ~/Documents/workspace/scratch]:node -v
v6.9.1
[Clays-MacBook-Pro ~/Documents/workspace/scratch]:

Of this code:

var async = require('async')
try {
    async.waterfall([function1, function2], myAsyncCallback);
}
catch(err) {
    console.log("THIS CODE IS NEVER EXECUTED.");
}

function function1(callback) {
    console.log("inside function1");
    var errMsg = "Uh oh";
   callback(new Error(errMsg), errMsg);
}

function function2(stuff2, callback) {
    console.log('inside function2');
    var errMsg = "Uh oh";
   callback(new Error(errMsg), errMsg);
}

function myAsyncCallback(err, result) {
    console.log("This code gets executed.");
    if (err) {
            console.log("This code gets executed too.");
            throw new Error("I want this error caught at the top around the catch around async.waterfall()");
        }
    console.log(result);
}

6 Comments

Your function1 and function2 are calling their callback synchronously, which makes no sense. myAsyncCallback is supposed to be an asynchronous callback, otherwise async.waterfall wouldn't have been used in the first place.
Bergi, I believe we are supposed to call callback in each function (e.g., hacksparrow.com/node-js-async-programming.html). to let us turn the normal async processing into synchronous. Maybe I am missing something.
@Clay, your sample worked for me. In an effort to test the error handling in my code, I added the throw statement in the callback, but I didn't also create the error and send it to the callback: callback(err). In my code there was an if/else in place of the "..." in my sample above that caused that callback call not to get executed.
In my example it is the throw that gets caught. Putting an error as the first argument of any callback function is simply a Node convention that async respects and knows to stop the chain of events. That would not end up in the catch block, which only handles thrown exceptions.
Clay, correct, but without calling "callback" with the err parameter, the "if (err)" in the callback method itself, including the throw statement, would not get executed. Your working sample made this clear to me that I wasn't really making the call despite my example above appearing to show that I had done so.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.