首页 > 解决方案 > setInterval 基于 ajax 结果或承诺状态

问题描述

我需要发送一个间隔为 5s 的 ajax 请求

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 触发时,前一个已经成功。如果前一个没有成功,那么只要前一个成功就开始一个新的间隔

我想出了这个解决问题的天真的想法

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需要超过 5s 才能成功,则计时器在成功之前开始计数asyncF

有没有成熟优雅的解决方案来解决问题?

标签: javascriptasynchronoustimersetinterval

解决方案


不使用 a 更容易做到这一点,setInterval并且必须确定何时取消/重新启动它,而是使用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 的异步函数没有什么不同。它的工作方式完全相同!

你应该看到

  • 当函数在 <5s 内成功时,它会等待 5s,因为原始开始再次触发
  • 当函数在 >5s 内成功时,它会立即重新启动
  • 当功能失败时,它会立即重新启动。

希望这符合您的要求

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()


推荐阅读