扩展Javascript承诺并在构造函数中解析或拒绝它

时间:2018-01-08 22:05:30

标签: javascript inheritance es6-promise es6-class

我想用ES6语法扩展本机Javascript Promise类,并能够在子类构造函数中调用一些异步函数。基于异步函数结果,必须拒绝或解决承诺。

但是,调用then函数时会发生两件奇怪的事情:

  1. 子类构造函数执行两次
  2. " Uncaught TypeError:Promise resolve或reject函数不可调用"错误被抛出
  3. 
    
        class MyPromise extends Promise {
            constructor(name) {
                super((resolve, reject) => {
                    setTimeout(() => {
                        resolve(1)
                    }, 1000)
                })
    
                this.name = name
            }
        }
    
        new MyPromise('p1')
            .then(result => {
                console.log('resolved, result: ', result)
            })
            .catch(err => {
                console.error('err: ', err)
            })
    
    
    

2 个答案:

答案 0 :(得分:6)

我发现兑现承诺的最好方法是

class MyPromise extends Promise {
    constructor(name) {
        // needed for MyPromise.race/all ecc
        if(name instanceof Function){
            return super(name)
        }
        super((resolve, reject) => {
            setTimeout(() => {
                resolve(1)
            }, 1000)
        })

        this.name = name
    }

    // you can also use Symbol.species in order to
    // return a Promise for then/catch/finally
    static get [Symbol.species]() {
        return Promise;
    }

    // Promise overrides his Symbol.toStringTag
    get [Symbol.toStringTag]() {
        return 'MyPromise';
    }
}


new MyPromise('p1')
    .then(result => {
        console.log('resolved, result: ', result)
    })
    .catch(err => {
        console.error('err: ', err)
    })

答案 1 :(得分:5)

推理很简单,但不一定是不言而喻的。

  • .then()返回承诺
  • 如果在Promise的子类上调用then,则返回的promise是子类的实例,而不是Promise本身。
  • 通过调用子类构造函数构造then返回的promise,并向其传递一个内部执行函数,该函数记录传递给它的resolvereject参数的值以供以后使用。
  • "后来使用"包括在监视thenonfulfilled处理程序(稍后)的执行时异步解析或拒绝onrejected返回的承诺,以查看它们是否返回值(解析返回的then承诺)或抛出错误(拒绝承诺)。

简而言之then次调用内部获取并记录对他们返回的承诺的resolvereject函数的引用。

<小时/> 所以关于这个问题,

new MyPromise( 'p1')

工作正常,是对子类构造函数的第一次调用。

.then( someFunction)

someFunction then调用列表中记录new MyPromise(召回then可多次调用)并尝试通过调用

new MyPromise( (resolve, reject) => ... /* store resolve reject references */

这是对来自then代码的子类构造函数的第二次调用。期望构造函数(并且确实)同步返回。

从创建返回的承诺返回时,.then方法进行完整性检查,以查看它以后需要的resolvereject函数是否实际上是函数。它们应该与then调用中提供的回调一起存储(在列表中)。

MyPromise的情况下,他们不是。由then传递给MyPromise的执行者甚至没有被调用。因此then方法代码会抛出类型错误&#34; Promise resolve或reject函数不可调用&#34; - 它无法解决或拒绝它应该返回的承诺。

在创建Promise的子类时,子类构造函数必须将执行函数作为其第一个参数,并使用实际resolvereject函数参数调用执行程序。这是then方法代码内部要求的。

做一些与MyPromise复杂的事情,也许检查第一个参数以查看它是否是一个函数并将其作为执行程序调用,如果是,可能是可行的,但不在本答案的范围内!对于显示的代码,编写工厂/库函数可能更简单:

&#13;
&#13;
function namedDelay(name, delay=1000, value=1) {
     var promise = new Promise( (resolve,reject) => {
         setTimeout(() => {
                resolve(value)
            }, delay)
         }
     );
    promise.name = name;
    return promise;
}

namedDelay( 'p1')
    .then(result => {
        console.log('fulfilled, result: ', result)
    })
    .catch(err => {
        console.error('err: ', err)
    })
&#13;
&#13;
&#13;

<小时/> 的; TLDR

Promise的类扩展不是扩展。如果是,则需要实现Promise接口并将执行器函数作为第一个参数。您可以使用工厂函数返回异步解析的Promise(如上所述),或 hack 使用

发布的代码
MyPromise.prototype.constructor = Promise

导致.then返回常规的Promise对象。黑客攻击本身驳斥了类扩展正在发生的想法。