最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 【node实战系列】编写一个重试装饰器

    正文概述 掘金(bigo大魔王)   2021-06-22   357

    【node实战系列】编写一个重试装饰器

    本文首发于:github.com/bigo-fronte… 欢迎关注、转载。

    背景

    bigo前端开始推广bff,hello农场作为首个bff落地项目,历经2个月,完成了从0-1的落地实践。

    【node实战系列】按照小模块拆分,从开发者的角度讲叙,如何进行bff高可用编码。

    本系列文章,基于eggjs框架编码,使用ts语法,为了提升阅读体验,建议大家先了解一下eggjs。

    系列文章

    • 【node实战系列】编写一个重试装饰器
    • 【node实战系列】自行实现应用缓存
    • 【node实战系列】异步并发,自定义Promise.allSettled
    • 【node实战系列】rpc与http协议通讯
    • 【node实战系列】使用reqId跟踪请求全流程日志
    • 【node实战系列】入参校验validate
    • 【node实战系列】异常中断
    • 【node实战系列】base64编码
    • 【node实战系列】服务发现
    • 【node实战系列】编码与约定
    • 【node实战系列】监控告警
    • 【node实战系列】单元测试
    • 【node实战系列】压测
    • 【node实战系列】灰度
    • 【node实战系列】文档
    • 【node实战系列】系列小结

    欢迎大家关注我们的github blog,持续更新。 github.com/bigo-fronte…

    为什么要重试

    这个很简单,项目开发中,调用第三方接口会因为网络延迟、异常导致调用的服务出错,重试几次可能就会调用成功(例如上传图片),所以需要一种重试机制进行接口重试来保证接口的正常执行。

    为什么要用装饰器

    其实我们可以在接口调用外面再包装一个重试方法,如下编码。

    /**
     *
     * @param {number} retries - 重试次数
     * @param {Function} fn - 重试函数
     */
    const retry = (retries, fn) => {
      fn().catch((err) => retries > 1 ? retry(retries - 1, fn) :  Promise.reject(err));
    };
    

    但是这种函数嵌套阅读起来不优雅,并且我们使用了ts进行编码,应该要物尽其用,发挥其装饰器能力。

    装饰器简单来说就是对类或者其属性进行拓展,便于添加额外的功能。

    什么是装饰器

    先来看一下retry装饰器在代码中是长成什么样子吧

    @retry(3, (res) => res.code !== 0)
    public async initFarm() {
      const res = await this.request({
        opType: Eoperator.BASE_INIT_FARM,
      });
      return res;
    }
    

    代码中@retry(3, (res) => res.code !== 0)就是一个装饰器了

    以 @ 作为标识符,可以作用于类,也可以作用于类的属性,具体使用原理请查看文档 www.tslang.cn/docs/handbo…

    方法装饰器

    我们的重试装饰器就是一个方法装饰器,我们先讲解一下方法装饰器的各属性

    下面是一个方法装饰器(@enumerable)的例子,应用于Greeter类的方法上:

    class Greeter {
        greeting: string;
        constructor(message: string) {
            this.greeting = message;
        }
    
        @enumerable(false)
        greet() {
            return "Hello, " + this.greeting;
        }
    }
    

    我们可以用下面的函数声明来定义@enumerable装饰器:

    function enumerable(value: boolean) {
        console.log(value); // 入参,false
        // target 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
        // propertyKey 成员的名字
        // descriptor 成员的属性描述符
        return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
          descriptor.enumerable = value;
        };
    }
    

    实现重试装饰器

    // 休眠,延迟执行
    function sleep(duration) {
      return new Promise((reslove) => setTimeout(reslove, duration))
    }
    /**
     * 重试装饰器
     *
     * @param {number} retries 重试次数
     * @param {*} cb 重试条件
     * @returns
     */
    export function retry(retries: number, cb) {
      return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        // 1. 保存原方法体
        const oldMethod = descriptor.value;
        // 2. 重新定义方法体
        descriptor.value = async function(...args) {
          // 重试
          const loop = async (count) => {
            // 3. 执行原来的方法体
            const res = await oldMethod.apply(this, args);
            if (count > 1 && cb(res)) {
              sleep(100); // 休眠100ms,再重试
              return loop(--count);
            } else {
              return res;
            }
          };
          return loop(retries);
        }
      }
    }
    

    小结

    回顾全文,我们发现一个小而美的重试装饰器就实现了,希望大家也可以动手,封装自己的装饰器。

    欢迎大家留言讨论,祝工作顺利、生活愉快!

    我是bigo前端,下期见。


    起源地下载网 » 【node实战系列】编写一个重试装饰器

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元