Matthieu
Matthieu

Reputation: 307

Executes functions async series

I'm trying to executes two functions async series with node.JS. But I don't understand to do this.

Now, I have:

function 1:

function search(client_id, callback) {
    clientRedis.keys('director:*', function (err, results) {
        results.forEach(function (key) {
            clientRedis.hgetall(key, function (err, obj) {
                //SAVE RESULT
                console.log('save');
            });
        });
    });
    callback(null, results);
}

function 2:

function range(client_id, callback) {
    //Sort my array
    callback(null, results);
}

And I call this functions here:

async.series([
    search(client_id),
    range(client_id);
], function (err, result) {
    console.log(err);
    console.log(result);
});

My problem: Second function is execute before the first because the first take more time. I need the result to first function to range my array with the function 2.

Upvotes: 1

Views: 1258

Answers (3)

zag2art
zag2art

Reputation: 5162

If you aren't going to use results of the first function inside the second one directly (only via redis) you can use something like this:

async.series([
    search.bind(null, client_id),
    range.bind(null, client_id)
], function (err, results) {
    console.log(err);
    console.log(results[0]); // for search results
    console.log(results[1]); // for range results
});

Upvotes: 1

throrin19
throrin19

Reputation: 18197

You should use async.waterfall instead of async.series to get first function result in second function.

Runs the tasks array of functions in series, each passing their results to the next in the array. However, if any of the tasks pass an error to their own callback, the next function is not executed, and the main callback is immediately called with the error.

And, you have a big mistakes in your code. If I understand your code, you want go to the second function after modify all your results and return this for the second function right ? In this case, use async.each instead of result.forEach and call the callback after the async each :

function search(client_id, callback) {
    clientRedis.keys('director:*', function (err, results) {
        var savedElems = [];
        async.each(results, function (key, done) {
            clientRedis.hgetall(key, function (err, obj) {
                if (err) {
                    return done(err);
                }
                savedElems.push(obj);
                done();
            });
        }, function (err) {
            if (err) {
                return callback(err);
            }
            callback(null, savedElems);
        });
    });
}

Upvotes: 0

Amadan
Amadan

Reputation: 198294

search(client_id) and range(client_id) will execute immediately, have callback argument assigned to undefined then async.series will try to execute the results of those functions as a series, and probably fail because those aren't functions, but undefined. Or rather, it would, if the functions didn't try to do undefined(null, results).

Keep in mind, if f is a function, f(...) executes it. You need to pass functions themselves to async.series, not results of their execution.

async.series wants you to pass in an array or object of tasks, each task being function(callback) { ... }.

Thus, the following should help:

async.series([
     function(callback) { search(client_id, callback); },
     function(callback) { range(client_id, callback); }
]...)

If you were writing in Haskell, that supports currying, your code would have been correct; but in JavaScript, f(x)(y) is not the same thing as f(x, y).

You also don't call callback from inside the Redis success function, which will also mess up your timing.

Upvotes: 0

Related Questions