Delays between promises in the promise chain

Let's say I use the following code to run multiple promises sequentially:

let paramerterArr = ['a','b','c','d','e','f'] parameterArr.reduce(function(promise, item) { return promise.then(function(result) { return mySpecialFunction(item); }) }, Promise.resolve()) 

The code simply calls mySpecialFunction (which returns the promise), expects the promise to be resolved, and then calls mySpecialFunction again, etc. Thus, the function is called once for each element of the array in the correct order.

How can I make sure that there is a delay of at least 50 milliseconds between each call to mySpecialFunction(item) ?

It is important that the promises run in the correct order, and the runtime of mySpecialFunction changes every time.

I assume that synchronous sleep will work, but I do not plan to run this code in a separate thread, so this will cause annoying ui freezes in the browser.

I am not sure if setTimer could be used for this. I mean, I cannot defer a promise.

+10
source share
7 answers

The answers are good, but they wait too long, since all the answers wait, regardless of whether the actual operation actually took more than 50 ms.

You can use Promise.all for it.

 const delay = ms => new Promise(resolve => setTimeout(resolve, ms)); let paramerterArr = ['a','b','c','d','e','f'] parameterArr.reduce(function(promise, item) { return promise.then(function(result) { return Promise.all([delay(50), mySpecialFunction(item)]); }) }, Promise.resolve()) 
+15
source

Actually a handy utility function that I call delay() :

 function delay(t, val) { return new Promise(function(resolve) { if (t <= 0) { resolve(val); } else { setTimeout(resolve.bind(null, val), t); } }); } 

Then you can use it in the promise chain as follows:

 let paramerterArr = ['a','b','c','d','e','f'] parameterArr.reduce(function(promise, item, index) { return promise.then(function(result) { // no delay on first iteration var delayT = index ? 50 : 0; return delay(delayT, item).then(mySpecialFunction); }) }, Promise.resolve()); 

You can also make a small useful function to do sequential iteration with extra delay:

 // delayT is optional (defaults to 0) function iterateSerialAsync(array, delayT, fn) { if (!fn) { fn = delayT; delayT = 0; } array.reduce(function(p, item, index) { return p.then(function() { // no delay on first iteration if (index === 0) delayT = 0; return delay(delayT, item).then(fn) }); }, Promise.resolve()); } 

And then you will use it as follows:

 iterateSerialAsync(paramerterArr, 50, mySpecialFunction).then(function(finalVal) { // all done here }); 
+3
source

To get a delay of at least 50 ms, use Promise.all :

 function delay(t) { return new Promise(function(resolve) { setTimeout(resolve, t); }); } parameterArr.reduce(function(promise, item) { return promise.then(function() { return Promise.all([ mySpecialFunction(item), delay(50) ]); }); }, Promise.resolve()); 
+2
source

The following is an example of how you could fulfill a promise that does not block, but waits for a certain period of time:

 function timedPromise(ms, payload) { return new Promise(function(resolve) { setTimeout(function() { resolve(payload); }, ms); }) } var time = Date.now(); timedPromise(1000) .then(function() { console.log(time - Date.now()); return timedPromise(2000); }).then(function() { console.log(time - Date.now()); return timedPromise(3000); }); 

So, depending on what you want, you should do something like this:

 let paramerterArr = ['a','b','c','d','e','f'] parameterArr.reduce(function(promise, item) { return promise.then(function(result) { return mySpecialFunction(item); }).then(function(specialResult) { return timedPromise(50, specialResult); }); }, Promise.resolve()) 
+1
source

Here you will find: https://jsbin.com/suvasox/edit?html,js,console

 let paramerterArr = ['a','b','c','d','e','f'] paramerterArr.reduce((p, val) => { return p.then(() => { return new Promise((res) => { setTimeout(() => { res(mySpecialFunction(val)); }, 1000); }); }); }, Promise.resolve()); 

p must be the result of p.then (). Only in this way do you link promises.

Please note that I changed it to 1000 ms just for emphasis.

+1
source

since this is apparently a requirement of mySpecialFunction , I would implement it. So the function is delayed if it is called less than 50 ms after the last call

 const delayBetweenCalls = (delay, fn) => { let lastCall = NaN; return function(/*...arguments*/){ //this and arguments are both forwarded to fn return new Promise(resolve => { let poll = () => { let delta = Date.now() - lastCall; if(delta < delay){ setTimeout(poll, delta - delay); }else{ lastCall = Date.now(); resolve( fn.apply(this, arguments) ); } } poll(); }) } } 

then

 const mySpecialFunction = delayBetweenCalls(50, function(some, ...args){ return someValueOrPromise; }); //and your loop stays the same: parameterArr.reduce(function(promise, item) { return promise.then(function(result) { return mySpecialFunction(item); }) }, Promise.resolve()) 

therefore it doesn't matter where / how mySpecialFunction is called, there will always be a delay of at least 50 ms before it runs the code inside the passed callback.

0
source

Here is my complete solution for deferred promise sequences:

 function timeout_sequence_promise(promises = [], timeout = 200) { //fake promise used as buffer between promises from params const delay = ms => new Promise(resolve => setTimeout(resolve, ms)); //we need to create array of all promises with delayed buffers let delayed_promises = []; let total = promises.length; let current = 0; //every odd promise will be buffer while (current < total) { delayed_promises.push(promises[current]); delayed_promises.push(delay(timeout)); current++; } return Promise.all(delayed_promises).then((result) => { //we need to filter results from empty odd promises return result.filter((item, index) => (index+2)%2 === 0); }); } 

As parameters, it receives an array of promises and a time delay in ms between them.

Hope this helps you!

0
source

Source: https://habr.com/ru/post/1013057/


All Articles