AndrePaganotto
AndrePaganotto

Reputation: 37

Await inside setInterval

I have a function that do some HTTP requests, i need to do them often every certain amount of time (in this case 5 seconds) if a certain condition is triggered.

What happens is that sometimes the requests that are inside the setInterval loop takes more than the specified time and the loop triggers again, calling the request again, without waiting for the previous to resolve.

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

I've already tried doing a recursive setTimeOut function like in this post, it worked but a few requests later it simply stopped working, not because a stack overflow happened but because IT SIMPLY STOPPED! The request was done, but it never brought the response back so the code stopped. And a few time before it stops it got slow.

I've also already tried using a setTimeOut inside a while loop but it seems that loops doesn't wait for intervals, not within this async context.

So the solution i need is: A way to every 5 seconds do the requests, but if it takes more than that to return the response, await for it.

Upvotes: 1

Views: 556

Answers (1)

Mario Vernari
Mario Vernari

Reputation: 7304

Well, here is a solution in order to keep the cycle period as most regular as possible. As long the responses arrive within the 5s timeout, the cycle polling should be pretty regular. However, if a response comes in late, the new request is made immediately it is processed.

I also added a try-catch block, because it is likely a chance having some error on a HTTP request (and also because you're doing other stuffs in the while). This leads you to decide how to behave in such a cases.

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

Upvotes: 1

Related Questions