给promise加上重试机制,无畏网络波动

92 阅读1分钟

Promise的重试是指在使用Promise进行异步操作时,如果操作失败,可以进行一定次数的重试,以尝试解决问题并获得成功的结果。

在JavaScript中,可以通过编写一个retry函数来实现Promise的重试功能。我们就直入主题吧,上老王的retry版。

// 封装的promise重试, input 函数应返回promise(如api请求)
function lwRetry(input, options) {
	const opt = Object.assign({
		retries: 3, // 重试次数
		leftRetries: options.retries ?? 3, // 剩余重试次数
		onFailedAttempt: async () => {},
		state: {} // 挂载自定义数据
	}, options)

	const attempt = async (opt) => {
		return input().catch(async err => {
			if (opt.leftRetries > 0) {
                // onFailedAttempt 如果抛出错误或者返回失败的promise,就会终止重试
				await opt.onFailedAttempt(err, opt);
				console.log(
					`总共可以尝试${ opt.retries }次,本次第${ opt.retries - opt.leftRetries + 1 }次尝试,还可以尝试${opt.leftRetries - 1}次`
					);
				opt.leftRetries--;
				return attempt(opt); // 形成一个重试promise链,直到重试次数用完或者成功
			} else {
				throw err;
			}
		})
	}

	return attempt(opt);
}

跑个例子


const fakeRequest = async () => {
	console.log('request...');
	if (Math.random() >= 0.5) return 'success';
	else throw new Error('Failed to fetch');
};

lwRetry(fakeRequest, {
	retries: 3,
	onFailedAttempt: async (error, opt) => {
		console.log('err', error.message, opt);
	}
}).then(res => {
	console.log('成功了', res);
}).catch(err => {
	console.log('失败了', err);
})

image.png

image.png

老王,这重试没有时间间隔好像不大行呀!!!

嗯,有点道理哈~

445EBF6E.png

function lwRetry(input, options) {
	const opt = Object.assign({
		retries: 3, // 重试次数
		leftRetries: options.retries ?? 3, // 剩余重试次数
		onFailedAttempt: async () => {},
                /* 加上重试时间间隔 */
                intervalFn(opt) {},
		state: {} // 挂载自定义数据
	}, options)

	const attempt = async (opt) => {
		return input().catch(async err => {
			if (opt.leftRetries > 0) {
                // onFailedAttempt 如果抛出错误或者返回失败的promise,就会终止重试
				await opt.onFailedAttempt(err, opt);
				console.log(
					`总共可以尝试${ opt.retries }次,本次第${ opt.retries - opt.leftRetries + 1 }次尝试,还可以尝试${opt.leftRetries - 1}次`
					);
				opt.leftRetries--;
                                const interval = opt.intervalFn(opt);
				console.log('===>interval', interval);
                                // 生成重试间隔时间...
                                if (interval && typeof interval === 'number') {
                                    return new Promise((resolve, reject) => {
                                        setTimeout( () => resolve(attempt(opt)), interval)
                                    })
                                }
				return attempt(opt); // 形成一个重试promise链,直到重试次数用完或者成功
			} else {
				throw err;
			}
		})
	}

	return attempt(opt);
}

image.png

更多的大家可以自由发挥,推荐一个库吧:p-retry 看了这个老王才想着试着写一个水篇文章。

image.png

可以去npm 或 github 看看代码