实现 Promise 的失败重试
目录
JS 组件 Promise 没有提供重试功能,因为一般前端开发不能容错,出错了要立即反馈给用户,让用户做选择。
重试处理一般用在硬件交互上,比如蓝牙、Wi-Fi、串口等。有时候它们可能会因为信号强度不够,出现失真之类的错误,这时需要像TCP那样,自己实现一套重发(重试)机制。
Snippet
withRetry
执行多次重试,返回 Promise。
-
如果执行中遇到 resolve 则停止重试并立即返回结果。
-
如果执行中遇到 reject 则准备下一次重试。
-
可以在执行过程用 stopRetry 停止之后的重试
/**
* @brief 执行重试,遇到 resolve 立即结束重试过程
*
* @param {number} retry 重试次数,至少 1
*
* @param {(stopRetry, currentRetry) => Promise} 执行方法
* @argument {stopRetry} 可以通过 stopRetry 停止之后的重试
* @argument {currentRetry} 当前重试次数,从 0 开始
*
* @returns Promise
*/
export default function withRetry<T = unknown>(
retry = 2,
fn: (stopRetry: () => void, currentRetry: number) => Promise<T>
) {
retry = Math.max(1, retry)
return new Promise<T>((resolve, reject) => {
let i = 0
let end = false,
lastErr = null
const action = () => {
if (i < retry && !end) {
fn(() => (end = true), i + 1)
.then(resolve)
.catch((err) => {
i++
lastErr = err
action()
})
} else {
reject(lastErr)
}
}
action()
})
}
Example
读资源,最多重试 5 次
withRetry(5, () => Promise((resolve, reject) => {
readResource('log.txt')
.then(content => resolve(content))
.catch(err => reject(err))
}))
.then(content => {
// resolve 传递的 content
})
.catch(err => {
// reject 传递最后一次的 err
})
读资源,最多重试 5 次,遇到超时则停止重试
withRetry(5, (stopRetry) => Promise((resolve, reject) => {
readResource('log.txt')
.then(content => resolve(content))
.catch(err => {
if (err === 'timeout') stopRetry();
reject(err)
})
}))
.then(...)
.catch(...)
读资源,最多重试 5 次,打印当前重试次数
withRetry(5, (stopRetry, currentRetry) => Promise((resolve, reject) => {
console.log(`当前重试: ${currentRetry}`); // 重试次数从 0 开始
readResource('log.txt')
.then(content => resolve(content))
.catch(err => reject(err))
}))
.then(...)
.catch(...)