Amey Zulkanthiwar
Amey Zulkanthiwar

Reputation: 85

Execute async code in the order it came in setInterval

I want to execute the code inside setInterval in an order it comes.

In real-time I am fetching data from different endpoints and I want to execute the code in the sequence it calls. response Time for some fetch request might be more so I want it to wait for the next call(fetch request) till the current request does not complete.

const s = 100;

/* Request number */
let seqN = 0;

const request = requestNumber =>
  // Request will be done from 1 to 5 seconds
  setTimeout(() => {
    out(`Refresh request number ${requestNumber} is done`);
  }, requestResponseTime(1, 6) * s);

setInterval(() => {
  request(seqN++);
}, 1 * s);

/**
 * Response time could take more than
 * interval time
 */
function requestResponseTime(min, max) {
  return Math.random() * (max - min) + min;
}

// Debug printing
out("Applicaiton started");
function out(message) {
  console.log(`${new Date().toUTCString()}: ${message}`);
}

Upvotes: 0

Views: 176

Answers (3)

Amey Zulkanthiwar
Amey Zulkanthiwar

Reputation: 85

I am able to achieve the functionality using recursion rather than the setInterval. I have given css code for this too so we can view the working properly.

index.js

import "./styles.css";
const s = 1000;

/* Request number */
let seqN = 0;

const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

function myData() {
  request(seqN++)
    .then(data => {
      out(data);
      delay(1 * s);
      myData();
    })
    .catch(err => {
      console.log("err", err);
      seqN--;
      myData();
      // out(err);  
    });
}
myData();

// Failed request simulation
// DON'T CHANGE THE CODE AFTER
function request(requestNumber) {
  return new Promise((resolve, reject) => {
    const isOK = Math.random() >= 0.5;

    setTimeout(
      () =>
        isOK
          ? resolve(`${requestNumber} is <strong>OK</strong>`)
          : reject(`${requestNumber} is <span>KO</span>`),
      requestResponseTime(1, 6) * s
    );
  });
}

/**
 * Response time could take more than
 * interval time
 */
function requestResponseTime(min, max) {
  return Math.random() * (max - min) + min;
}

// Debug printing
out("Applicaiton started");

function out(message) {
  // console.log(`${new Date().toUTCString()}: ${message}`);
  document.getElementById(
    "app"
  ).innerHTML += `<pre>${new Date().toUTCString()}: ${message}</pre>`;
}

style.css

body {
  font-family: sans-serif;
}

strong {
  color: green;
}

span {
  color: red;
}

Upvotes: 0

meisam
meisam

Reputation: 485

well there are two ways first is that you make the first call and wait for response then you make the second call, the other is that you make all the calls first but you do your operation on them on the order they were called. I am guessing you are looking for the second one, so if they are all fetch calls you can do it like this:

function async sequentialCalls() {
  const firstCall = fetch(first);
  const secondCall = fetch(second);
  const thirdCall = fetch(third);

  const firstRespone = await firstCall
    ....operation on firstResponse

  const secondRespone = await secondCall
    ....operation on secondResponse

  const thirdRespone = await thirdCall
    ....operation on thirdResponse
}

as for the setTimeout I think you need to promisify the response to be able to use it with await

Upvotes: 0

CreativeJoe
CreativeJoe

Reputation: 73

If I get your question well, you want to only execute a new request after the previous one has been completed?

OR

You are worried about setInterval being fired even when the previous one request hasn't been completed?

If yes, then you need to have a checker/flag that would check if the previous request has been completed or not.

A quick example would be:

var isLoading = false;
setInterval(() => {
 if(isLoading === true) return; // more like do nothing
 else {
  isLoading = true;
  // call your request function here
 }
}, 1 * s)

Ensure not to put the checker/flag inside your setInterval/setTimeout call. make it a global variable as you did for your seqN. This way it's content would only change when something actually happens.

Also, ensure to set isLoading to false inside your request function as soon as your request function is done processing.

Upvotes: 1

Related Questions