How to call function at fixed interval with ensuring previous function is completed

Viewed 752

I have a Promise based function which i want to call at fixed interval, Lets say at every 60 seconds. But i also want to make sure that function is called only if the previously called function is executed completely and i want to continue this for infinite time

function fun(){
    return new Promise((resolve,reject)=>{
        //Some database queries which may or may not complete in 60 seconds
        resolve("done")
    })
}

setInterval(()=>{
    fun().then(d=>{
        console.log(d)
    })
},60000)

Above code will not check for previously called function is completed or not. but i want to make sure that

3 Answers

class AsyncQueue {
  constructor() {
    this.queue = null;
  }

  push(task) {
    // If we have task in query, append new at the end, if not execute immediately
    // Every task appended to existing queue will be executed immediately after previous one is finished
    return this.queue = this.queue ? this.queue.then(() => task()) : task();
  }
}

const task = (id) => () => new Promise((resolve) => {
  console.log('Task', id, 'started');
  // Random time betwen 500-1300ms
  const time = Math.round(Math.random() * 800 + 500);
  setTimeout(() => {
    console.log("Finished task '" + id + "' after " + time + "ms");
    resolve();
  }, time);
});
const queue = new AsyncQueue();
let id = 0;
// This will push new task to queue every 1s
setInterval(() => {
  console.log("Pushing new task", ++id);
  queue.push(task(id));
}, 1000);

Of course we can implement it without using class

let queue;
function push(task) {
  return queue = queue ? queue.then(() => task()) : task();
}
// or
const push = (task) => queue = queue ? queue.then(() => task()) : task();

Well, if you want to wait until it has finished, you should call it again after the promise has resolved. So you would then change from setInterval to setTimeout instead.

For the purpose of this question, I did change the timeout to 1 second instead

function fun(){
    return new Promise((resolve,reject)=>{
        //Some database queries which may or may not complete in 60 seconds
        resolve("done")
    })
}

function self() {
  setTimeout(()=>{
      fun().then(d=>{
          console.log(d)
      }).then( self ); // call the setTimeout function again
  },1000);
}

self();

Of course, choose a better name than self, it was like the only thing I could come up with on short notice :)

Update

I think I misunderstood the question originally, so you only want to call it again if it really did complete, and not wait until it finished and then have the new interval start.

In that case, you can rather do something like this instead:

function fun(){
  fun.running = true;
  return new Promise((resolve,reject)=>{
      //Some database queries which may or may not complete in 60 seconds
      resolve("done");
  });
}

setInterval(()=>{
  // just make sure the fun isn't running
  if (!fun.running) {
    fun()
      .then(d=> console.log(d) )
      .catch( err => console.log( err ) ) // error handling here to make sure the next block is run
      .then( () => {
        // and handle the reset of the flag here
        fun.running = false;
      } );
  }
},1000);

Instead of calling the function in setInterval call it with setTimeout after response is received.

function fun(){
    return new Promise((resolve,reject)=>{
        //Some database queries which may or may not complete in 60 seconds
        resolve("done")
    })
}
//Function to call promise function recursively
function functionCaller(fn){
fn()
.then((response)=>{
   console.log(response)
   setTimeout(() => functionCaller(fn), 6000)
})
}

functionCaller(fun)

Related