Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

breaking the waterfall chain without throwing an error #11

Closed
c2c533c4f237 opened this issue Feb 15, 2011 · 8 comments
Closed

breaking the waterfall chain without throwing an error #11

c2c533c4f237 opened this issue Feb 15, 2011 · 8 comments

Comments

@c2c533c4f237
Copy link

I was told I need to refactor my code that is using async waterfall. I used it primarily because I had several chained functions that were going too deep, and I wanted to reuse a function, etc. There is a condition at one point down the chain that is not strictly an error condition, but that I don't want to pass down the rest of the waterfall chain, because it's useless - say for example I did a query and there are no results, and that's not an error, I don't want to propagate all the way down with no results. If I were doing this without async, I guess I would have a "final" callback and which could be called to break out of the chain without explicitly throwing an error. This functionality doesn't seem to be present in waterfall. Is there a way to do this cleanly? The only way I can see to do it is to throw a special error and then handle that on the final callback so as to return a non error.

@rjack
Copy link

rjack commented Jun 27, 2011

Hi,

you probably solved your issue by now, btw this is my approach:

var flow = [
    async.apply(...),
    // ...
];

async.waterfall(flow, function (err) {
    if (err === 'ok') return;
    // handle error
});

When a function calls a callback with err = 'ok', the final callback of the waterfall intercepts it.

@pvsundarram
Copy link

I have a similar issue & i am adding a callback wrapper(which i could avoid) just to check whether its an error or not for every waterfall that i use. Its not that clean when there are more than one waterfalls.
Can the callback function itself have another property called 'final', which people could call to go to the end.
Some thing like

function search (cond, callback) {
  async.waterfall([function (cb) {
      db.get(cond, cb);
    },
    function (res, cb) {
      if (!res || !res.length)
        return cb.final();
      //do something useful
    }
  ], callback);
}

i wont have to wrap the callback & it could be chained to rest of the program.

@tax
Copy link

tax commented May 20, 2012

@caolan is there anything you dont like about @jnordberg pull request? And if so is there something I can do to get this pull request accepted?

@anguyen8
Copy link

@tax : actually I found that we can skip to the final function by passing 'error' = true like this:

async.waterfall([function (callback) {
callback(null); // <--- go to next fn
},
function (callback) {
callback(true); // <--- skip to the last fn
},
function (callback) {
callback(null); // <--- this fn will not be called
}
], callback);

@tax
Copy link

tax commented May 24, 2012

@tot2ivn thanks for the tip!

@Enome
Copy link

Enome commented May 27, 2012

If you set the error the result will be empty though.

var async = require('async');

async.waterfall( [
  function( callback ){
    console.log('one');
    callback( null );
  },

  function( callback ){
    console.log('two');
    callback( true, 'more info' );
  },

  function( callback ){
    console.log('three');
    callback( null );
  }
], function(err, result){
  console.log( err, result );
} );

// RESULT
// one
// two
// true undefined

@brianmaissy
Copy link
Contributor

In light of @caolan's comment upon closing pull request #85, this issue should probably be closed

@caolan caolan closed this as completed Mar 2, 2013
@digitaljohn
Copy link

Personally I find myself needing functionality like this and think it should be added to the core library.

Here is my helper workaround if anyone is interested...

exports.breakWaterfall = function(tasks, callback){
    async.waterfall(tasks, function(){
        if(arguments[0] === 'break'){
            arguments[0] = null;
        }
        callback.apply(null, arguments);
    });
}

If you need to break to the last function within a task just call the callback like this: done('break', other, arguments);.

The helper just detects the 'break' and mutates the arguments so it does not look like an error to the rest of your code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants