Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

node js pass context to callback

Tags:

node.js

I am using node.js. I have this handlers.js file:

exports.Handlers = function(prefix) {
    this.prefix = prefix;
    this.db = new DBInstance();
};

exports.Handlers.prototype.getItemById = function(id) {
    var item = this.db.getItemById(id, function(error, item) {
        item.name = this.prefix + item.name;
        ...
        ...
    });
};

When I call:

var h = new Handlers();
h.getItemById(5);

I get an error since the context isn't the Handlers and this.prefix doesn't exists. I can fix it using this:

exports.Handlers.prototype.getItemById = function(id) {
    var scope = this;
    var item = this.db.getItemById(id, function(error, item) {
        item.name = scope.prefix + item.name;
        ...
        ...
    });
};

Is there any better way to pass the context to the callback? What is the nodejs common way to pass the context to the callback?

like image 522
Naor Avatar asked Jan 26 '13 19:01

Naor


2 Answers

Node implements ECMAScript 5, which has Function.bind().

I think that is what you are looking for.

exports.Handlers.prototype.getItemById = function(id) {
    var item = this.db.getItemById(id, (function(error, item) {
        item.name = this.prefix + item.name;
        ...
        ...
    }).bind(this)); //bind context to function
};

This works, however when using a closure as a callback, like you are doing, the most common way this is done is by storing the context in a variable that can be used in the closure.

This method is more common because many times callbacks can be deep and calling bind on each callback can be heavy; whereas defining self once is easy:

SomeObject.prototype.method = function(id, cb) {
    var self = this;
    this.getSomething(id, function(something) {
        //self is still in scope
        self.getSomethingElse(something.id, function(selse) {
            //self is still in scope and I didn't need to bind twice
            self.gotThemAll(selse.id, cb);
        });
    });
};
like image 179
Chad Avatar answered Oct 19 '22 01:10

Chad


This problem is not related to Node.js, it's a general problem in JavaScript - and you already figured out the usual solution in JavaScript: Bind the this context to another variable (the one that you called scope), and use that within the callback to access the outer context.

Common names for this variable include that and self.

There may be a solution in ECMAScript 6 (codename "harmony") with the so-called fat-arrow operator that binds a function to an outer context. If you want to play with it today you might want to check out TypeScript, a pre-compiler for JavaScript made by Microsoft which focuses on ES6-compatible syntax. Then your callback becomes something such as

foo(() => { console.log(this.bar); });

instead of:

var that = this;
foo(function () { console.log(that.bar); });

Just for the sake of completeness: jQuery's (and other frameworks) bind function generally works similar. See http://api.jquery.com/bind/ for an example.

HTH.

like image 44
Golo Roden Avatar answered Oct 19 '22 00:10

Golo Roden