轮询是前端开发过程当中经常会遇到,它是一种模拟服务器主动推送消息的场景。在一次高德面试题中给定两个 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();
发表评论