【问题标题】:Await inside setInterval在 setInterval 内等待
【发布时间】:2021-05-29 03:02:50
【问题描述】:

我有一个函数可以做一些HTTP requests,如果触发了某个条件,我需要每隔一定的时间(在本例中为 5 秒)经常执行它们。

发生的情况是,有时setInterval 循环内的请求花费的时间超过指定的时间,循环再次触发,再次调用请求,而不等待前一个解决。

function doRequests() {
    setInterval(async () => {
        
        //Sometimes the following line takes more than 5 seconds to return its promise
        const response = await myRequestFunction();

        // do something with response...

        if(/*certain condition is triggered*/)
        {
            //Call the function again
            doRequests();
        }

    }, 5000);
}

doRequests();

我已经尝试过像 this 帖子中那样执行递归 setTimeOut 函数,它可以工作,但在一些请求之后它就停止了工作,不是因为 stack overflow 发生了,而是因为它简单地停止了!请求已完成,但它从未返回响应,因此代码停止了。在它停止前几次它变慢了。

我也已经尝试在 while 循环中使用 setTimeOut,但似乎循环不会等待间隔,而不是在此异步上下文中。

所以我需要的解决方案是: 每 5 秒执行一次请求的方法,但如果返回响应所需的时间超过此时间,请等待它。

【问题讨论】:

  • 使用 setTimeout 代替
  • 注意:您并没有清除间隔,因此每次调用函数时都会创建越来越多的间隔。
  • "请求已完成,但它从未返回响应" - 修复该问题。您不能让它在下一次迭代之前等待响应,并且如果响应从未发生,则期望循环继续。
  • 查看thisthat 以了解async/await 用法的正确示例

标签: javascript asynchronous async-await settimeout setinterval


【解决方案1】:

好吧,这里有一个解决方案,可以尽可能地保持循环周期。只要响应在 5s 超时内到达,循环轮询应该是非常有规律的。但是,如果响应迟到,则会立即发出新请求。

我还添加了一个 try-catch 块,因为它可能会在 HTTP 请求上出现一些错误(也因为您在此期间正在做其他事情)。这将引导您决定在这种情况下如何表现。

async function doRequests() {
    let answered = false;
    let expired = false;

    //start the timer
    let tmr = setTimeout(function() {
        if (answered) {
            //response already received (and processed), so start a new request
            doRequest();
        }
        else {
            //mark the timer as expired
            expired = true;
        },
        5000
    );

    try {
        const response = await myRequestFunction();

        // do something with response...

        if(/*certain condition is triggered*/)
        {
            answered = true;
            if (expired) {
                //Call the function again
                doRequests();
            }
        }
    }
    catch (err) {
        //error trapped: clear timeout
        clearTimeout(tmr);

        if (/* decide to continue as it was fine */) {
            answered = true;
            if (expired) {
                //Call the function again
                doRequests();
            }
        }
    }
}

doRequests();

【讨论】:

  • 我已经使用 setTimeOut 解决了它,我没有正确使用递归,所以由于某种堆栈滞后它突然停止了。但现在我已经弄清楚如何使用。谢谢你的回答:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-02-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-03
相关资源
最近更新 更多