Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

async.waterfall bind context

I am currently working on a web application with node.js and I can't figure a context problem with the library async.

Here is a example of code of my application :

notification.prototype.save = function (callback) {

    async.parallel([
        // Save the notification and associate it with the doodle
        function _saveNotification (done) {

            var query = 'INSERT INTO notification (notification_id, user_id, doodle_id, schedule_id) values (?, ?, ?, ?)';
            notification.db.execute(query, [ this.notification_id, this.user_id, this.doodle_id, this.schedule_id ], { prepare : true }, function (err) {
                return done(err);
            });

            console.log("SAVE NOTIFICATION");
            console.log("doodle_id", this.doodle_id);

        }.bind(this),

        // Save notification for the users with the good profile configuration
        function _saveNotificationForUsers (done) {
            this.saveNotificationForUsers(done);
        }.bind(this)

    ], function (err) {
        return callback(err);
    });
};

So in this code, I have to use the bind method to bind the context of my object ( this ) because otherwise async change it. I got it. But what I don't understand is why the code of this.saveNotificationForUsers does not work the same way :

notification.prototype.saveNotificationForUsers = function (callback) {

    console.log("SAVE NOTIFICATION FOR USERS");
    console.log("doodle id : ", this.doodle_id);

    async.waterfall([
        // Get the users of the doodle
        function _getDoodleUsers (finish) {
            var query = 'SELECT user_id FROM users_by_doodle WHERE doodle_id = ?';
            notification.db.execute(query, [ this.doodle_id ], { prepare : true }, function (err, result){
                if (err || result.rows.length === 0) {
                    return finish(err);
                }

                console.log("GET DOODLE USERS");
                console.log("doodle id : ", this.doodle_id);

                return finish(err, result.rows);
            });
        }.bind(this)
    ], function (err) {
        return callback(err);
    });
};

When I call the previous code, the first console.log is able to show me the "this.doodle_id" variable, which means the function knows the "this" context. But the functions inside the waterfall call does not, even if I bind 'this' to them.

I figured a way to make it works by creating a 'me' variable which is equal to 'this' juste before I call waterfall, and by binding the functions with the 'me' variable' and not this, but I would like to understand why I am forced to do this when I use async.waterfall and not when I use async.parallel.

I hope I was clear with the description of my problem, if someone can help me understand it will be a great pleasure !

like image 665
Orodan Avatar asked Apr 20 '15 09:04

Orodan


1 Answers

The problem you’re seeing has got nothing to do with parallel or waterfall but rather how in the waterfall case, you’re referencing this in the callback to notification.db.execute, whereas in the parallel case, there is only a call to done in there. You could use bind again to bind that callback as well:

async.waterfall([
    function _getDoodleUsers (finish) {
        //…
        notification.db.execute(query, [ this.doodle_id ], { prepare : true }, function (err, result){
            //…
        }.bind(this)); // <- this line
    }.bind(this)
], function (err) {
    //…
});
like image 198
Raphael Schweikert Avatar answered Sep 22 '22 09:09

Raphael Schweikert