需求描述
在服务端经常会遇到异常故障,对于重要业务我们会对异常进行捕获,并进行重试或回退尝试。
例如,短信服务。当我们调用第三方的短信服务由于网络超时,导致调用API失败无法给用户下发验证码。通常,我们会使用try...catch
捕获异常,并执行一次补发。但是可能由于网络异常再次失败。那么,如何实现多次重试策略呢。
实现思路
实现 retry
的核心思想是,递归调用。
代码实现
初级版
/**
*
* @param {number} retries - 重试次数
* @param {Function} fn - 重试函数
*/
const retry = (retries, fn) => {
fn().catch((err) => retries > 1 ? retry(retries - 1, fn) : Promise.reject(err));
};
增强版 - 增加延迟重试
// 首先实现一个暂停函数
const pause = (duration) => new Promise((reslove) => setTimeout(reslove, duration));
const backoff = (retries, fn, delay = 500) => {
fn().catch((err) => retries>1
? pause(delay).then(() => backoff(retries-1, fn, delay))
: Promise.reject(err)
);
}
总结
在实现pause
函数时,始终不明白后半部分代码的含义,为什么setTimeout(reslove, duration)
可以直接传一个reslove
。
后来才想明白,setTimeout
第一个参数是需要延迟执行的函数,而reslove
本身就是一个函数。
最后,附上 setTimeout
的API文档
* `callback` 当定时器到点时要调用的函数。
* `delay` 调用 `callback` 之前要等待的毫秒数。
* `...args` 当调用 `callback` 时要传入的可选参数
setTimeout(callback, delay[, ...args])
预定在 `delay` 毫秒之后执行的单次 `callback`。 返回一个用于 [`clearTimeout()`](http://nodejs.cn/s/L4L2Xr) 的 `Timeout`。
`callback` 可能不会精确地在 `delay` 毫秒被调用。 Node.js 不能保证回调被触发的确切时间,也不能保证它们的顺序。 回调会在尽可能接近所指定的时间上调用。
注意:当 `delay` 大于 `2147483647` 或小于 `1` 时,`delay` 会被设为 `1`。
如果 `callback` 不是一个函数,则抛出 [`TypeError`](http://nodejs.cn/s/Z7Lqyj)