需求描述
在服務(wù)端經(jīng)常會遇到異常故障墅茉,對于重要業(yè)務(wù)我們會對異常進(jìn)行捕獲,并進(jìn)行重試或回退嘗試件豌。
例如,短信服務(wù)控嗜。當(dāng)我們調(diào)用第三方的短信服務(wù)由于網(wǎng)絡(luò)超時(shí)茧彤,導(dǎo)致調(diào)用API失敗無法給用戶下發(fā)驗(yàn)證碼。通常疆栏,我們會使用try...catch
捕獲異常曾掂,并執(zhí)行一次補(bǔ)發(fā)惫谤。但是可能由于網(wǎng)絡(luò)異常再次失敗。那么珠洗,如何實(shí)現(xiàn)多次重試策略呢溜歪。
實(shí)現(xiàn)思路
實(shí)現(xiàn) retry
的核心思想是,遞歸調(diào)用许蓖。
代碼實(shí)現(xiàn)
初級版
/**
*
* @param {number} retries - 重試次數(shù)
* @param {Function} fn - 重試函數(shù)
*/
const retry = (retries, fn) => {
fn().catch((err) => retries > 1 ? retry(retries - 1, fn) : Promise.reject(err));
};
增強(qiáng)版 - 增加延遲重試
// 首先實(shí)現(xiàn)一個(gè)暫停函數(shù)
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)
);
}
總結(jié)
在實(shí)現(xiàn)pause
函數(shù)時(shí)蝴猪,始終不明白后半部分代碼的含義,為什么setTimeout(reslove, duration)
可以直接傳一個(gè)reslove
膊爪。
后來才想明白自阱,setTimeout
第一個(gè)參數(shù)是需要延遲執(zhí)行的函數(shù),而reslove
本身就是一個(gè)函數(shù)米酬。
最后沛豌,附上 setTimeout
的API文檔
* `callback` 當(dāng)定時(shí)器到點(diǎn)時(shí)要調(diào)用的函數(shù)。
* `delay` 調(diào)用 `callback` 之前要等待的毫秒數(shù)赃额。
* `...args` 當(dāng)調(diào)用 `callback` 時(shí)要傳入的可選參數(shù)
setTimeout(callback, delay[, ...args])
預(yù)定在 `delay` 毫秒之后執(zhí)行的單次 `callback`加派。 返回一個(gè)用于 [`clearTimeout()`](http://nodejs.cn/s/L4L2Xr) 的 `Timeout`。
`callback` 可能不會精確地在 `delay` 毫秒被調(diào)用爬早。 Node.js 不能保證回調(diào)被觸發(fā)的確切時(shí)間哼丈,也不能保證它們的順序。 回調(diào)會在盡可能接近所指定的時(shí)間上調(diào)用筛严。
注意:當(dāng) `delay` 大于 `2147483647` 或小于 `1` 時(shí)醉旦,`delay` 會被設(shè)為 `1`。
如果 `callback` 不是一個(gè)函數(shù)桨啃,則拋出 [`TypeError`](http://nodejs.cn/s/Z7Lqyj)