Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extending Promise to support Progress reporting

So I wanted to extend Promise to have a 'progress' part so that i can report progrss with it while using Promise for my Async tasks.

Thus I extended Promise like this:

class promisePro extends Promise {
    constructor(fn) {
        super(function (resolve, reject) {
            fn(resolve, reject, this._progress.bind(this));
        });
    }

    _progress(v) {
        if (this.progressCB)
            this.progressCB(v);
    }

    progress(fn) {
        this.progressCB = fn;
    }
}

and used it:

function ptest() {
    return new promisePro((resolve, reject, progress) => {
        setTimeout(() => {
            progress(0.3)
        }, 1000)
        setTimeout(() => {
            progress(0.6)
        }, 2000)
        setTimeout(() => {
            progress(0.9)
        }, 3000)
        setTimeout(() => {
            resolve(1)
        }, 4000)
    })
}

and used itt:

ptest().then((r) => {
    console.log('finiished: ' + r)
}).progress((p) => {
    console.log('progress: ' + p)
})

and got this error:

ptest().then((r) => {
    ^
TypeError: Promise resolve or reject function is not callable

What am i doing wrong here?

I was using node 7.5, updated to 8.4. Got that error in both versions.

Thanks.

like image 234
ajlajlajl Avatar asked Oct 17 '22 06:10

ajlajlajl


1 Answers

there are a couple of issues to look out for here.

firstly, the "this" keyword is undefined until the super function is called. therefore you could change the constructor to something like below, using a function to reference an instantiated variable to sel

constructor(fn) {
    let self;
    super(function (resolve, reject) {
        fn(resolve, reject, value => self._progress(value));
    });
    self = this;
}

secondly, keep in mind you are extending the promise type, so when you are calling the "then" function on it, it will return a new promise object, not your new promise type, so the progress function is undefined there. a way to avoid this is to return "this" in the progress function, and in the usage to use the progress function before then, as below

progress(fn) {
    this.progressCB = fn;
    return this;
}

and for the usage

ptest().progress((p) => {
    console.log('progress: ' + p)
}).then((r) => {
    console.log('finiished: ' + r)
})

but now you will lose the benefit of the promise and won't be able to chain more promises with progress (still, depends on your use case).

As a suggestion for a different approach, have you tried using Observables? http://reactivex.io/rxjs/

like image 64
Tal Avatar answered Oct 31 '22 01:10

Tal