轮询是前端开发过程当中经常会遇到,它是一种模拟服务器主动推送消息的场景。在一次高德面试题中给定两个 async 函数,让使用前端代码模拟轮询查询的场景,当时还是比较慌得一批的,写了个残次品。二话不说咱们看要求:
// 1. 每隔 3 秒请求一次,成功返回结果,失败继续重试
// 2. 如果请求未在 3秒 内返回,直接超时并继续重试
// 3. 10 秒超时直接返回
const fakeFetch = async (params) => {}
const requestFn = async (params) => {}最开始想简单了,一顿定时器操作完成之后,被反问了几个问题之后,感觉这个功能涉及考点还真挺多:
1、时间重置问题:fakeFetch 在模拟延时的情况下,只要超过 3 秒就永远查不到结果;
2、异步机制问题:await fakeFetch() 在请求等待过程中,后面的定时器无法启动;
以下是面试结束之后优化的结果,已通过 chrome 测试通过。
const fakeFetch = async (params) => {
if (!fakeFetch.status) {
fakeFetch.status = 'prepare'; // 响应状态 prepare: 已就绪, pendding: 响应中
fakeFetch.timeout = 4000; // 指定接口超时时间
fakeFetch.data = undefined; // 返回返回数据
}
if (fakeFetch.status === 'prepare') {
fakeFetch.data = await new Promise((resolve, reject) => {
fakeFetch.status = 'pendding';
// 模拟接口请求时间
setTimeout(() => {
fakeFetch.status = undefined;
resolve({ status: 200, msg: 'success', data: '这是一堆业务数据' })
}, fakeFetch.timeout);
});
}
return fakeFetch.data;
};
const requestFn = async (params) => {
let data, timer1, timer2, times = 1;
clearInterval(timer1);
clearTimeout(timer2);
// 轮询处理
timer1 = setInterval(async () => {
if (data) {
console.log(data); // 成功返回结果
clearInterval(timer1);
clearTimeout(timer2);
return;
}
console.log('第 ' + (++times) + ' 次发起请求!');
data = await fakeFetch(params); // 重试
}, 3000);
// 超时处理
timer2 = setTimeout(() => {
clearInterval(timer1);
clearTimeout(timer2);
console.error('超时'); // 超时
}, 10000);
// 发起模拟网络请求
console.log('第 ' + (times) + ' 次发起请求!');
data = await fakeFetch(params); // 第一次发起请求
};
requestFn();
发表评论