javascript - 扩展 Javascript promise 并在构造函数中解决或拒绝它

标签 javascript inheritance es6-promise es6-class

我想用 ES6 语法扩展原生 Javascript Promise 类,并且能够在子类构造函数中调用一些异步函数。根据异步函数结果,promise 必须被拒绝或解决。

然而,当 then 发生了两件奇怪的事情。函数被调用:

  • 子类构造函数执行两次
  • “Uncaught TypeError: Promise resolve or reject function is not callable” 抛出错误


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

    最佳答案

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

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

  • 总之then内部调用获取并记录对 resolve 的引用和 reject它们返回的 promise 的函数。

    所以关于这个问题,
    new MyPromise( 'p1')
    
    工作正常,是对子类构造函数的第一次调用。
    .then( someFunction)
    
    记录 someFunctionthen 的列表中调用 new MyPromise 的电话(记忆 then 可以多次调用)并尝试通过调用来创建返回 promise
    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 的子类时,子类的构造函数必须以一个执行器函数作为其第一个参数,并以真实的 resolve 调用执行器。和 reject函数参数。这是 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 接口(interface)并将执行器函数作为第一个参数。您可以使用工厂函数返回异步解析的 Promise(如上),或 黑客 发布的代码与
    MyPromise.prototype.constructor = Promise
    
    导致 .then返回一个常规的 Promise 对象。 hack 本身驳斥了正在发生类扩展的想法。

    promise 扩展示例
    以下示例显示了一个基本的 Promise 扩展,它添加了提供给构造函数的属性。注意:
  • Symbol.toString getter仅影响将实例转换为字符串的输出。在测试的浏览器控制台上记录实例对象时,它不会将“Promise”更改为“MyPromise”。
  • Firefox 89 (Proton) 没有报告扩展实例的自身属性,而 Chrome 报告了 - 下面的测试代码按名称记录实例属性的原因。

  • class MyPromise extends Promise {
        constructor(exec, props) {
            if( typeof exec != "function") {
                throw TypeError( "new MyPromise(executor, props): an executor function is required");
            }
            super((resolve, reject) => exec(resolve,reject));
            if( props) {
                Object.assign( this, props);
            } 
        }
        get [Symbol.toStringTag]() {
            return 'MyPromise';
        }
    }
    
    // Test the extension:
    const p1 = new MyPromise( (resolve, reject) =>
        resolve(42),
        {id: "p1", bark: ()=>console.log("woof") });
    
    console.log( "p1 is a %s object", p1.constructor.name);
    console.log( "p1.toString() = %s", p1.toString());
    console.log( "p1.id = '%s'", p1.id);
    console.log( "p1 says:"); p1.bark();
    
    const pThen = p1.then(data=>data);
    console.log( "p1.then() returns a %s object", pThen.constructor.name);
    let pAll = MyPromise.all([Promise.resolve(39)]);
    console.log( "MyPromise.all returns a %s object", pAll.constructor.name);
    try { new MyPromise(); }
    catch(err) {
        console.log( "new MyPromise() threw: '%s'", err.message);
    }

    关于javascript - 扩展 Javascript promise 并在构造函数中解决或拒绝它,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48158730/

    相关文章:

    Java 继承和转换

    javascript - 坚决 promise 并拒绝作为属性(property),这是一种反模式吗?为什么?

    javascript - Nodejs Promise 有更好的方法来处理 Promise 实现中发生的错误吗?

    javascript - 在 JavaScript 闭包中使用 Promise 与 Web Worker 一起工作

    javascript - 可以更改部分字母的衬线吗?

    javascript - Facebook JS API 错误

    ios - iOS 基础 View Controller 的组合与继承

    接受派生类对象的派生类中的 C++ Enforce 函数

    javascript - 如何在 javascript 而不是 jquery 中更改父 div 的 css

    javascript - 无法将 ASP.NET/MVC "Model"成员抓取到我的 JQuery 函数中