Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Object method with ES6 / Bluebird promises

I am using node v0.11.14-nightly-20140819-pre on Windows with harmony flag.

I have JavaScript object with two methods defined in its prototype:

function User (args) {
    this.service= new Service(args);
}

User.prototype.method2 = function (response) {
    console.log(this); // <= UNDEFINED!!!!
};

User.prototype.method1 = function () {
    .............
    this.service.serviceMethod(args)
        .then(this.method2)
        .catch(onRejected);
};

function onRejected(val) {
    console.log(val);
}

serviceMethod of Service object returns a promise.

When I use User object like below:

let user = new User(args);
user.method1();

this in method2 of object User ends up undefined when called by then once promise is fulfilled.

I tried using both ES6 and Bluebird promise implementation.

Why this ends up being undefined in this case?

like image 481
krl Avatar asked Nov 26 '14 12:11

krl


People also ask

What is Bluebird promise?

What is Bluebird JS? Bluebird JS is a fully-featured Promise library for JavaScript. The strongest feature of Bluebird is that it allows you to “promisify” other Node modules in order to use them asynchronously. Promisify is a concept applied to callback functions.

What does promise Promisify do?

promisify. Returns a function that will wrap the given nodeFunction . Instead of taking a callback, the returned function will return a promise whose fate is decided by the callback behavior of the given node function.

What is Promisifyall?

Promisifies the entire object by going through the object's properties and creating an async equivalent of each function on the object and its prototype chain. The promisified method name will be the original method name suffixed with suffix (default is "Async" ).

How do you use a promise map?

map. Given a finite Iterable (arrays are Iterable ), or a promise of an Iterable , which produces promises (or a mix of promises and values), iterate over all the values in the Iterable into an array and map the array to another using the given mapper function.


2 Answers

Why this ends up being undefined in this case?

Because you're passing a function, not a method-bound-to-an-instance. This problem is not even promise-specific, see How to access the correct `this` context inside a callback? for the generic solution:

….then(this.method2.bind(this))… // ES5 .bind() Function method

….then((r) => this.method2(r))… // ES6 arrow function

However, Bluebird does offer an other way to call the function as a method:

this.service.serviceMethod(args)
    .bind(this)
    .then(this.method2)
    .catch(onRejected);
like image 148
Bergi Avatar answered Oct 18 '22 14:10

Bergi


I should add that this is a generic Javascript issue and can also be solved using plain javascript features. For example, you could also do this:

User.prototype.method1 = function () {
    .............
    this.service.serviceMethod(args)
        .then(this.method2.bind(this))
        .catch(onRejected);
};

This uses Function.prototype.bind() which is built into Javascript and present on every function. This creates a function stub (which is what is passed to .then() and that stub will automatically reattach the desired this value before calling method2().

like image 6
jfriend00 Avatar answered Oct 18 '22 12:10

jfriend00