首页 文章

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

提问于
浏览
3

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

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

  • 子类构造函数执行两次

  • “未捕获TypeError:Promise解析或拒绝函数不可调用”抛出错误

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)
    })

1 回答

  • 2

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

    • .then() 返回一个承诺

    • 如果在Promise的子类上调用 then ,则返回的promise是子类的实例,而不是Promise本身 .

    • then 返回的promise是通过调用子类构造函数构造的,并向它传递一个内部执行函数,该函数记录传递给它的 resolvereject 参数的值以供以后使用 .

    • "later use"涵盖在监视 onfulfilledonrejected 处理程序(稍后)的执行时异步解析或拒绝 then 返回的承诺,以查看它们是否返回值(解析 then 返回的承诺)或抛出错误(拒绝承诺) .

    简而言之, then 调用内部获取并记录对它们返回的promise的 resolvereject 函数的引用 .


    关于这个问题,

    new MyPromise( 'p1')
    

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

    .then( someFunction)
    

    new MyPromisethen 调用列表中记录 someFunction (可以多次调用 then )并尝试通过调用创建返回承诺

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

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

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

    MyPromise 的情况下,他们不是 . 由 then 传递给 MyPromise 的执行程序甚至不被调用 . 所以 then 方法代码抛出一个类型错误"Promise resolve or reject function is not callable" - 它无法解析或拒绝它应该返回的promise .

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

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

    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)
        })
    

    ;TLDR

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

    MyPromise.prototype.constructor = Promise
    

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

相关问题