基于 ajax 结果或承诺状态的 setInterval
setInterval based on ajax result or promise state
我需要发送一个ajax请求,间隔5s
const asyncF = async () => { await /* some ajax stuff */ }
asyncF(); // fire off an ajax request first
setInterval(() => { // start an interval
asyncF();
}, 5 * 1000);
通常 asyncF
应该在 5 秒内成功,因此连续启动之间的 5 秒通常是可以的并且很简单,但我想确保下一个 asyncF 触发时,前一个已经成功。如果前一个没有成功,那么每当前一个成功时开始一个新的间隔
- 如果
asyncF
不到5秒就成功了,一切都很好!
- 如果
asyncF
需要超过5秒才能成功,我需要清除间隔并在asyncF
成功时开始新的间隔
- 如果
asyncF
在5s内失败,我也需要立即再次调用并设置新的间隔
我想出了这个解决问题的天真的想法
let flag = true; // global variable flag
const asyncF = async () => {
await /* some ajax stuff */
flag = true;
}
try {
asyncF();
setTimer();
} catch {
asyncF();
setTimer();
}
function setTimer() {
let timer = setInterval(() => {
if (flag) {
asyncF();
} else {
clearInterval(timer);
timer = setTimer();
}
}, 5 * 1000);
return timer;
}
但是使用这种方法,如果 asyncF
需要超过 5 秒才能成功,计时器会在 asyncF
成功之前 开始计时
有没有什么成熟优雅的方案可以解决问题?
不使用 setInterval
更容易做到这一点,并且必须计算出何时 cancel/restart 它,但是使用 setTimeout
.
这个想法是你设置一个 5 秒的计时器,如果之前的功能已经完成,你就可以调用该功能。如果在函数执行时达到超时,则立即执行它,如果发生错误也是如此。
async function limitedFunction(){
let isRunning = true;
let timeoutReached = false;
setTimeout( () => {
timeoutReached = true;
if(!isRunning)
limitedFunction();
},5000);
try{
await asyncF();
isRunning = false;
if(timeoutReached)
limitedFunction();
}
catch {
limitedFunction();
}
}
在下面的示例中,我模拟了您的 asyncF
函数,它随机地成功或失败(80% 的成功机会)并且有一个随机延迟,有时会超过 5 秒。然而,这与基于 ajax 的异步函数没有什么不同。它的工作方式完全相同!
你应该看到
- 当函数在 <5 秒内成功时,它会等待 5 秒,因为原始函数再次开始触发
- 当函数在 >5 秒内成功时,它会立即再次启动
- 当函数失败时,它会立即重新启动。
希望这符合您的要求
async function asyncF(){
const delay = (ms) => new Promise(resolve => setTimeout(resolve,ms))
const rndFunc = Math.random();
const rndTime = Math.floor((Math.random() * 7) + 1);
if(rndFunc < 0.8){
console.log(`asyncF will succeed in ${rndTime}s`)
await delay(rndTime*1000)
}
else{
console.log(`asyncF will fail in ${rndTime}s`);
await delay(rndTime*1000)
throw "I failed"
}
}
async function limitedFunction(){
let isRunning = true;
let timeoutReached = false;
setTimeout( () => {
timeoutReached = true;
if(!isRunning)
limitedFunction();
},5000);
try{
await asyncF();
isRunning = false;
if(timeoutReached)
limitedFunction();
}
catch {
limitedFunction();
}
}
limitedFunction()
我需要发送一个ajax请求,间隔5s
const asyncF = async () => { await /* some ajax stuff */ }
asyncF(); // fire off an ajax request first
setInterval(() => { // start an interval
asyncF();
}, 5 * 1000);
通常 asyncF
应该在 5 秒内成功,因此连续启动之间的 5 秒通常是可以的并且很简单,但我想确保下一个 asyncF 触发时,前一个已经成功。如果前一个没有成功,那么每当前一个成功时开始一个新的间隔
- 如果
asyncF
不到5秒就成功了,一切都很好! - 如果
asyncF
需要超过5秒才能成功,我需要清除间隔并在asyncF
成功时开始新的间隔 - 如果
asyncF
在5s内失败,我也需要立即再次调用并设置新的间隔
我想出了这个解决问题的天真的想法
let flag = true; // global variable flag
const asyncF = async () => {
await /* some ajax stuff */
flag = true;
}
try {
asyncF();
setTimer();
} catch {
asyncF();
setTimer();
}
function setTimer() {
let timer = setInterval(() => {
if (flag) {
asyncF();
} else {
clearInterval(timer);
timer = setTimer();
}
}, 5 * 1000);
return timer;
}
但是使用这种方法,如果 asyncF
需要超过 5 秒才能成功,计时器会在 asyncF
成功之前 开始计时
有没有什么成熟优雅的方案可以解决问题?
不使用 setInterval
更容易做到这一点,并且必须计算出何时 cancel/restart 它,但是使用 setTimeout
.
这个想法是你设置一个 5 秒的计时器,如果之前的功能已经完成,你就可以调用该功能。如果在函数执行时达到超时,则立即执行它,如果发生错误也是如此。
async function limitedFunction(){
let isRunning = true;
let timeoutReached = false;
setTimeout( () => {
timeoutReached = true;
if(!isRunning)
limitedFunction();
},5000);
try{
await asyncF();
isRunning = false;
if(timeoutReached)
limitedFunction();
}
catch {
limitedFunction();
}
}
在下面的示例中,我模拟了您的 asyncF
函数,它随机地成功或失败(80% 的成功机会)并且有一个随机延迟,有时会超过 5 秒。然而,这与基于 ajax 的异步函数没有什么不同。它的工作方式完全相同!
你应该看到
- 当函数在 <5 秒内成功时,它会等待 5 秒,因为原始函数再次开始触发
- 当函数在 >5 秒内成功时,它会立即再次启动
- 当函数失败时,它会立即重新启动。
希望这符合您的要求
async function asyncF(){
const delay = (ms) => new Promise(resolve => setTimeout(resolve,ms))
const rndFunc = Math.random();
const rndTime = Math.floor((Math.random() * 7) + 1);
if(rndFunc < 0.8){
console.log(`asyncF will succeed in ${rndTime}s`)
await delay(rndTime*1000)
}
else{
console.log(`asyncF will fail in ${rndTime}s`);
await delay(rndTime*1000)
throw "I failed"
}
}
async function limitedFunction(){
let isRunning = true;
let timeoutReached = false;
setTimeout( () => {
timeoutReached = true;
if(!isRunning)
limitedFunction();
},5000);
try{
await asyncF();
isRunning = false;
if(timeoutReached)
limitedFunction();
}
catch {
limitedFunction();
}
}
limitedFunction()