Search code examples
javascriptnode.jsasynchronoussynchronizationsynchronous

node.js - how do I run a series of callback functions in order?


like many other peoples, I want to turn a async function of a third party module (Patio) into a sync function.

function get_user_message_list(parameters, array, response)
{
var new_array = [];
for (var i in array) {

    var json = array[i];
    json['content']['users_seen'] = ["1757842565"];
    json['content']['users_not_seen'] = [];

    new_array.push(json);
}

console.log("NEW ARRAY :");
console.log(new_array);

response.writeHeader(200, {'Content-Type':'application/json'});
response.end(JSON.stringify(new_array));
}

function get_json_message(parameters, json)
{
console.log("JSON OBJECT :");
console.log(json);
var dataset = db.from(TABLES.USER).join(TABLES.MOVIE_LIST, {MLUserId: sql.URId}).join(TABLES.MOVIE, {MVId: sql.MLMovieId});

dataset.where('MLSeen={seen} AND MVSourceId={movie} AND MVSource={source} AND URId!={user}', {seen: 1, movie: json['content']['movie_id'], source: json['content']['movie_source'], user:parameters.FACEBOOK_ID}).all().then(function(users){
    if (users) {
        for (var j in users) {
            json['content']['users_seen'].push(users[j].URId);
        }
    }

    //console.log(json['content']['users_seen']);

    dataset.where('MLSeen={seen} AND MVSourceId={movie} AND MVSource={source} AND URId!={user}', {seen: 0, movie: json['content']['movie_id'], source: json['content']['movie_source'], user:parameters.FACEBOOK_ID}).all().then(function(users){
        if (users) {
            for (var j in users) {
                json['content']['users_not_seen'].push(users[j].URId);
            }
        }

        console.log(json);
    }, errorHandler);
}, errorHandler);
}

In the get_user_message_list function I iterate into an array and for each iteration I calling the async function. In this async function I'm using Patio module to make request to MySQL database. But like you can see, I must wait for the query result to be get after sending a result to the previous function.

How can I wait for the query result to be got before I send it to the next function?


Solution

  • You CAN and you SHOULD turn async functions into something that behaves like sync functions when a problem needs to be fixed. You can't is never the correct answer, the shouldn't is for the programmer to answer.

    So, I recently found some code in the nodeunit module which may help you. It fires the async functions, keep track of which are ready. After all requests are in, fires the callback. This could be the idea behind the solution to your problem (so no, this is not the final solution).

    async.forEachSeries = function (arr, iterator, callback) {
        if (!arr.length) {
            return callback();
        }
        var completed = 0;
        var iterate = function () {
            iterator(arr[completed], function (err) {
                if (err) {
                    callback(err);
                    callback = function () {};
                }
                else {
                    completed += 1;
                    if (completed === arr.length) {
                        callback();
                    }
                    else {
                        iterate();
                    }
                }
            });
        };
        iterate();
    };
    

    This test triggered me to see how it was done:

    exports['series'] = function (test) {
        var call_order = [];
        async.series([
            function (callback) {
                setTimeout(function () {
                    call_order.push(1);
                    callback(null, 1);
                }, 25);
            },
            function (callback) {
                setTimeout(function () {
                    call_order.push(2);
                    callback(null, 2);
                }, 50);
            },
            function (callback) {
                setTimeout(function () {
                    call_order.push(3);
                    callback(null, 3, 3);
                }, 15);
            }
        ],
        function (err, results) {
            test.equals(err, null);
            test.same(results, [1, 2, [3, 3]]);
            test.same(call_order, [1, 2, 3]);
            test.done();
        });
    };
    

    Happy programming!