本文首发于: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前端,下期见。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!