Tuesday, July 30, 2019

Delay Processing of a List Using JavaScript Promise without Recursion

In many cases, we'd like to perform a list of actions with delay in between. (Ex: to make a list of API calls without overloading the server.) However, JavaScript has no sleep function, but it is provided with a setTimeout method callback after a delay. Typically tail recursion can be applied at the end of function to trigger another setTimeout for the next execution. However this makes code ugly and can be avoided by using Promise. The setTimeout function can be easily wrapped into a promise to provide delay by:

function promiseDelay(miliseconds) { return new Promise((resolve) => { setTimeout(resolve, miliseconds)})}


To use this function to delay your call, just place the logic inside .then() method

promiseDelay(1000).then(() => {console.log('hello')})


When there's a list of values to be processed, we can keep chaining new deplayPromise at the end of the promise:


p = Promise.resolve(undefined)
[1,2,3].forEach(x=> {
  p = p.then(() => promiseDelay(1000).then(() => {console.log(x)}) )
})
This is a little hard to read, as there is .then() inside a .then(). Note that the next execution is not depending on the result of the delay, this is equivalent to wrap the execution into another promise, and use Promise.all() to ensure both delay and execution to be both completed before proceeding:

function promiseDisplay(x) {
  return new Promise((resolve) => { console.log(x); resolve()})
}

Promise.all([promiseDelay(1000), promiseDisplay(x)]);

Applying the above change, the code now looks nice: