扩展承诺以支持进度报告

ajl*_*ajl 5 javascript node.js promise

因此,我想扩展Promise以获得"进度"部分,以便我可以使用Promise为我的异步任务报告它的进度.

因此我像这样扩展了Promise:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

并使用它:

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)
    })
}
Run Code Online (Sandbox Code Playgroud)

并使用itt:

ptest().then((r) => {
    console.log('finiished: ' + r)
}).progress((p) => {
    console.log('progress: ' + p)
})
Run Code Online (Sandbox Code Playgroud)

并得到此错误:

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

我在这做错了什么?

我使用的是节点7.5,更新到8.4.两个版本都有错误.

谢谢.

小智 3

这里有几个问题需要注意。

首先,“this”关键字在调用 super 函数之前是未定义的。因此,您可以将构造函数更改为如下所示,使用函数引用实例化变量来 sel

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

其次,请记住您正在扩展 Promise 类型,因此当您对其调用“then”函数时,它将返回一个新的Promise 对象,而不是新的 Promise 类型,因此进度函数在那里未定义。避免这种情况的一种方法是在进度函数中返回“this”,并在使用之前使用进度函数,如下所示

progress(fn) {
    this.progressCB = fn;
    return this;
}
Run Code Online (Sandbox Code Playgroud)

以及用途

ptest().progress((p) => {
    console.log('progress: ' + p)
}).then((r) => {
    console.log('finiished: ' + r)
})
Run Code Online (Sandbox Code Playgroud)

但现在您将失去承诺的好处,并且无法将更多承诺与进度联系起来(仍然取决于您的用例)。

作为不同方法的建议,您是否尝试过使用 Observables? http://reactivex.io/rxjs/