Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The `this` object is undefined when using promise [duplicate]

In the bellow example, when I am running this code, calling the start function, only inside _one function this is defined. When continuing to the next function _two, this is undefined. Any explanation? And how to solve this? Thanks in advance.

'use strict';

class MyClass {
    constructor(num) {
        this.num = num;
    }

start() {
    this._one()
    .then(this._two)
    .then(this._three)
    .then(this._four)
    .catch((err) => {
        console.log(err.message);
    });
}

_one() {
    console.log('num: ' + this.num);
    return new Promise((resolve, reject) => {
        resolve();
    });
}
_two() {
    console.log('num: ' + this.num);
    return new Promise((resolve, reject) => {
        resolve();
    });
}
_three() {
    console.log('num: ' + this.num);
    return new Promise((resolve, reject) => {
        resolve();
    });
}
_four() {
    console.log('num: ' + this.num);
    return new Promise((resolve, reject) => {
        resolve();
    });
}
}


let myClass = new MyClass(4);
myClass.start();
like image 929
Saro Avatar asked Mar 16 '26 08:03

Saro


2 Answers

Modify the promises chain to this:

start() {
    this._one()
    .then(this._two.bind(this))
    .then(this._three.bind(this))
    .then(this._four.bind(this))
    .catch((err) => {
        console.log(err.message);
    });
}

The bind() will modify handlers to bind with the correct this object (the instance of MyClass). You will achieve the method invocation on MyClass instance.

Following your initial scenario, the Promise will invoke the handlers (_two, _three) as regular functions, which in Strict mode will have this as undefined.

See here more details about bind().

like image 68
Dmitri Pavlutin Avatar answered Mar 17 '26 22:03

Dmitri Pavlutin


I am personnaly using bluebird promises rather then native ES6. This promises perform faster (https://github.com/petkaantonov/bluebird/tree/master/benchmark), have more convinient API and available in both browsers and node.js (http://bluebirdjs.com/docs/getting-started.html) I am bind this value to the first promise in chain - after that your example works well

'use strict';
var Promise = require('bluebird');

class MyClass {
    constructor(num) {
        this.num = num;
    }

    start() {
        Promise.bind(this)
        .then(this._one)
        .then(this._two)
        .then(this._three)
        .then(this._four)
        .catch((err) => {
            console.log(err.message);
        });
    }

    _one() {
        console.log('num: ' + (this.num += 1));
        return new Promise((resolve, reject) => {
            resolve();
        });
    }
    _two() {
        console.log('num: ' + (this.num += 2));
        return new Promise((resolve, reject) => {
            resolve();
        });
    }
    _three() {
        console.log('num: ' + (this.num += 3));
        return new Promise((resolve, reject) => {
            resolve();
        });
    }
    _four() {
        console.log('num: ' + (this.num += 4));
        return new Promise((resolve, reject) => {
            resolve();
        });
    }
}


let myClass = new MyClass(4);
myClass.start();    

I've also changed methods slightly so that you can see progress in this.num

like image 35
Vlad Ankudinov Avatar answered Mar 17 '26 21:03

Vlad Ankudinov