Asutosh
Asutosh

Reputation: 1828

How to schedule multiple timeout functions

I have a scenario where I need to schedule multiple timeouts in vanilla JS, it will be something like this below:

const scheduler = {
  done: function() {},
  schedule: function() {}
};
scheduler.schedule(function(done) {
  setTimeout(() => {
    console.log(1);
    done()
  }, 2000);
});
scheduler.schedule(function(done) {
  setTimeout(() => {
    console.log(2);
    done()
  }, 1000);
});
scheduler.schedule(function(done) {
  setTimeout(() => {
    console.log(3);
    done()
  }, 3000);
});


it should execute it in such a way that it must print below:

1
2
3

Upvotes: 3

Views: 485

Answers (3)

FZs
FZs

Reputation: 18619

This is a nice use case of promises.

These objects allow the abstraction over asynchronous operations, and fortunately, can be chained.

const scheduler = {
  last: Promise.resolve(),
  schedule(cb){
    this.last = this.last.then(() => new Promise(cb))
  }
}
scheduler.schedule(function(done) {
  setTimeout(() => {
    console.log(1);
    done()
  }, 2000);
});
scheduler.schedule(function(done) {
  setTimeout(() => {
    console.log(2);
    done()
  }, 1000);
});
scheduler.schedule(function(done) {
  setTimeout(() => {
    console.log(3);
    done()
  }, 3000);
});

However, if you use this with promises you obtained from elsewhere , it can quickly turn into the Explicit Promise construction antipattern, so, for a more general code, move the new Promise() part out of the schedule method:

const scheduler = {
  last: Promise.resolve(),
  schedule(cb){
    this.last = this.last.then(cb)
  }
}
scheduler.schedule(function() {
  return new Promise(done => {
    setTimeout(() => {
      console.log(1);
      done()
    }, 2000);
  })
});
scheduler.schedule(function() {
  return new Promise(done => {
    setTimeout(() => {
      console.log(2);
      done()
    }, 1000);
  })
});
scheduler.schedule(function() {
  return new Promise(done => {
    setTimeout(() => {
      console.log(3);
      done()
    }, 3000);
  })
});

Upvotes: 3

GirkovArpa
GirkovArpa

Reputation: 4912

const scheduler = {
  done: function (cb) {
    cb();
    this.timeouts.shift();
    this.timeouts[0] && this.timeouts[0]();
  },
  schedule: function (cb, ms) {
    const timeout = () => setTimeout(this.done.bind(this), ms, cb);
    this.timeouts.push(timeout) == 1 && timeout();
  },
  timeouts: [],
};

scheduler.schedule(() => console.log('1'), 2000);
scheduler.schedule(() => console.log('2'), 1000);
scheduler.schedule(() => console.log('3'), 3000);

Upvotes: -1

Elias Schablowski
Elias Schablowski

Reputation: 2812

You would need a que for the timeouts, eg:

const scheduler = {
    done:function(){}, // Not sure what this function is supposed to do
    schedule:function(callback, timeout) {
        scheduler.que.push([callback, timeout]); // Add the function along with its wait time
        if(scheduler.que.length == 1) scheduler.startQue(); // If the que was previously empty, start the execution of the que
    },
    startQue() {
        setTimeout(() => {
            scheduler.que[0][0](); // run the callback timeout
            scheduler.que.shift(); // Remove the just ran timeout
            if(scheduler.que.length >= 1) scheduler.startQue(); // Start another timeout if we still have some in the que
        }, scheduler.que[0][1]);
    },
    que: []
};
scheduler.schedule(() => console.log(1), 2000); // Wait for 2 seconds to print
scheduler.schedule(() => console.log(2), 1000); // Wait 1 second after the first one printed
scheduler.schedule(() => console.log(3), 3000); // Wait another 3 seconds after the second one

Upvotes: 1

Related Questions