jjzjj

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

coder 2024-07-24 原文

我想用 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/

    有关javascript - 扩展 Javascript promise 并在构造函数中解决或拒绝它的更多相关文章

    1. ruby - 使用 C 扩展开发 ruby​​gem 时,如何使用 Rspec 在本地进行测试? - 2

      我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当

    2. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

      我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

    3. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

      我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

    4. ruby - 在 Ruby 中有条件地定义函数 - 2

      我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

    5. c - mkmf 在编译 C 扩展时忽略子文件夹中的文件 - 2

      我想这样组织C源代码:+/||___+ext||||___+native_extension||||___+lib||||||___(Sourcefilesarekeptinhere-maycontainsub-folders)||||___native_extension.c||___native_extension.h||___extconf.rb||___+lib||||___(Rubysourcecode)||___Rakefile我无法使此设置与mkmf一起正常工作。native_extension/lib中的文件(包含在native_extension.c中)将被完全忽略。

    6. 屏幕录制为什么没声音?检查这2项,轻松解决 - 2

      相信很多人在录制视频的时候都会遇到各种各样的问题,比如录制的视频没有声音。屏幕录制为什么没声音?今天小编就和大家分享一下如何录制音画同步视频的具体操作方法。如果你有录制的视频没有声音,你可以试试这个方法。 一、检查是否打开电脑系统声音相信很多小伙伴在录制视频后会发现录制的视频没有声音,屏幕录制为什么没声音?如果当时没有打开音频录制,则录制好的视频是没有声音的。因此,建议在录制前进行检查。屏幕上没有声音,很可能是因为你的电脑系统的声音被禁止了。您只需打开电脑系统的声音,即可录制音频和图画同步视频。操作方法:步骤1:点击电脑屏幕右下侧的“小喇叭”图案,在上方的选项中,选择“声音”。 步骤2:在“声

    7. 【高数】用拉格朗日中值定理解决极限问题 - 2

      首先回顾一下拉格朗日定理的内容:函数f(x)是在闭区间[a,b]上连续、开区间(a,b)上可导的函数,那么至少存在一个,使得:通过这个表达式我们可以知道,f(x)是函数的主体,a和b可以看作是主体函数f(x)中所取的两个值。那么可以有,  也就意味着我们可以用来替换 这种替换可以用在求某些多项式差的极限中。方法: 外层函数f(x)是一致的,并且h(x)和g(x)是等价无穷小。此时,利用拉格朗日定理,将原式替换为 ,再进行求解,往往会省去复合函数求极限的很多麻烦。使用要注意:1.要先找到主体函数f(x),即外层函数必须相同。2.f(x)找到后,复合部分是等价无穷小。3.要满足作差的形式。如果是加

    8. ruby - 在 Ruby 中按名称传递函数 - 2

      如何在Ruby中按名称传递函数?(我使用Ruby才几个小时,所以我还在想办法。)nums=[1,2,3,4]#Thisworks,butismoreverbosethanI'dlikenums.eachdo|i|putsiend#InJS,Icouldjustdosomethinglike:#nums.forEach(console.log)#InF#,itwouldbesomethinglike:#List.iternums(printf"%A")#InRuby,IwishIcoulddosomethinglike:nums.eachputs在Ruby中能不能做到类似的简洁?我可以只

    9. C51单片机——实现用独立按键控制LED亮灭(调用函数篇) - 2

      说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时

    10. 深度学习部署:Windows安装pycocotools报错解决方法 - 2

      深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal

    随机推荐