今天看到简书上一个动态,有道题挺感兴趣的,我把原来的链接发出来:
请实现一个功能’ omniPoller ', 用来模拟真实的轮询
我把要求列出来:
omniPoller
函数接受两个参数:queryStatus
和successCallback
queryStatus
是一个返回true
或false
的函数successCallback
是一个函数,应该在queryStatus
返回true
时调用。omniPoller
应该定期调用queryStatus
- 当调用一把
queryStatus
即成功时,即一次就返回true
,则直接执行成功回调 - 当
queryStatus
返回false时,它会等待一段时间并再次调用queryStatus
,直到queryStatus
返回true
- 第一次失败后,于1秒后重新调用
queryStatus
函数,如再失败,往后均为1.5s后再次调取 - 当
queryStatus
返回true
时,调用successCallback
并退出函数
- 当调用一把
例如:
- 初次直接请求接口,正常请求,如成功直接退出,如失败,则按照下面步骤:
- 第一次失败: 1秒后,调用’ queryStatus ‘,返回’ false ’
- 第二次失败: 再过1.5秒后,调用’ queryStatus ‘,返回’ false ’
- 第三次失败: 再过1.5秒后,调用’ queryStatus ‘,它返回’ false ’
- 第四次失败: 再过1.5秒后,调用’ queryStatus ‘,返回’ true ‘,执行’ successCallback ',退出
首先看一下原作者代码:
var num = 1;
function omniPoller(queryStatus,Callback){
let timer = 1000;
let cleartime = setInterval(() => {
if(num!=1){
timer = timer*1.5;
}
console.log(timer)
let status = queryStatus();
if(status){
Callback();
clearInterval(cleartime)
}
}, timer);
}
function queryStatus(){
num+=1;
return num==5?true:false;
}
function successCallback(){
console.log("成功")
}
omniPoller(queryStatus,successCallback);
原作者的问题有如下几个问题:
cleartime
中的num
和timer
的获取和设置由于是同步的,设置的时候你会发现,timer
永远都是1000就打印了queryStatus
去模拟查询结果,其实用parseInt(Math.random() * 2)
更好- 如果用户一把就获取成功拿到值的话,是不需要设置定时器的,所以你这写法没有处理好一次就获取成功的可能性
为了真实的模拟接口的真实性,咱们用js中Math
的random
方法来模拟接口随机返回true
和false
,同时用ES6中的async
和await
方法来模拟同步操作,我把修改后的逻辑修改如下:
/**
* omniPoller模拟接口请求逻辑
* 当接口返回true时则执行成功回调,
* 当接口请求失败时,第一次后等1秒重新请求,接口返回true时则执行成功回调,如若再次失败则以后每次等5000秒后重新请求,直至成功
*/
var num = 1;
async function omniPoller(queryStatus, successCallback) {
await queryStatus().then((data) => {
successCallback(data);
}).catch( err => {
setTimeout(() => {
omniPoller(queryStatus, successCallback);
},num == 2 ? 1000 : 5000)
})
}
function queryStatus() {
return new Promise((reslove,reject) => {
let status = parseInt(Math.random() * 2);
if (status != 1) {
console.log(`第${num}次请求失败,需要发送第${num + 1}次请求`);
++num;
reject('01');
} else {
console.log(`第${num}次请求成功`);
reslove('00');
}
})
}
function successCallback(data) {
console.log(data)
}
omniPoller(queryStatus, successCallback);
运行结果如下: