Reputation: 3923
I have an array. I can loop over it with the foreach method.
data.forEach(function (result, i) {
url = data[i].url;
request(url);
});
The request function is making a http request to the given url. However making all these requests at the same time leads to all sorts of problems.
So I thought I should slow things down by introducing some-sort of timer.
But I have no idea how will be able to combine a forach loop with setTimeOut/setInterval
Please note am doing this on the server (nodejs) rather on the browser.
Thanks for you help.
Upvotes: 7
Views: 7052
Reputation: 958
a very simple solution for quick throttling using async / await is to create a promise such as :
const wait = (delay) => new Promise((resolve, _) => {
setTimeout(() => resolve(true), delay)
})
Then await for it when you need to pause (in an async
function):
//... loop process
await wait(100)
Note: you need to use a for
loop for this to work, a forEach
won't wait.
Upvotes: 0
Reputation: 361
Some addings to this questions, just for knowledge base.
Created and async version without recursion.
function onceEvery(msTime) {
return {
doForEach: function (eachFunc, paramArray) {
var i = 0, Len = paramArray.length;
(function rekurse() {
if (i < Len) {
eachFunc(paramArray[i], i, paramArray);
setTimeout(rekurse, msTime);
++i;
}
})();
},
doForEachAsync: async function (eachFunc, paramArray, staticParamenters) {
var i = 0, Len = paramArray.length;
while (i < Len) {
await (async function rekurse() {
await eachFunc(paramArray[i], staticParamenters);
setTimeout(() => { }, msTime);
++i;
})();
}
}
};
}
module.exports = {
onceEvery
};
Put this code in a .js and call as simple as:
await throttle.onceEvery(100).doForEachAsync(loadJobFunction, arrayParam, { staticParam1, staticParam2, staticParam3 });
Upvotes: 0
Reputation: 5322
Many of the above solutions, while practical for a few requests, unfourtunatly choke up and brick the page when dealing with tens of thousands of requests. Instead of queuing all of the timers at one, each timer should be qued sequentially one after another. If your goal is to have nice pretty fluffy code with lots of sugar and 'goodie-goodies' then below is the solution for you.
function miliseconds(x) { return x }
function onceEvery( msTime ){
return {
doForEach: function(arr, eachF){
var i = 0, Len = arr.length;
(function rekurse(){
if (i < Len) {
eachF( arr[i], i, arr );
setTimeout(rekurse, msTime);
++i;
}
})();
}
};
}
Nice, pretty, fluffy sugar-coated usage:
onceEvery(
miliseconds( 150 )
).doForEach(
["Lorem", "ipsum", "dolar", "un", "sit", "amet"],
function(value, index, array){
console.log( value, index );
}
)
function miliseconds(x) { return x }
function onceEvery( msTime ){
return {
doForEach: function(arr, eachF){
var i = 0, Len = arr.length;
(function rekurse(){
if (i < Len) {
eachF( arr[i], i, arr );
setTimeout(rekurse, msTime);
++i;
}
})();
}
};
}
Upvotes: 1
Reputation: 664196
As your problem is global, you should adjust your request
function to have only 5 request running at a time - using a global, static counter. If your request was before something like
function request(url, callback) {
ajax(url, callback);
}
now use something like
var count = 0;
var waiting = [];
function request(url, callback) {
if (count < 5) {
count++;
ajax(url, function() {
count--;
if (waiting.length)
request.apply(null, waiting.shift());
callback.apply(this, arguments);
});
} else
waiting.push(arguments);
}
Upvotes: 8
Reputation: 48761
Instead of setTimeout
could have them run in sequence. I assume there's a callback
parameter to your request()
function.
function makeRequest(arr, i) {
if (i < arr.length) {
request(arr[i].url, function() {
i++;
makeRequest(arr, i);
});
}
}
makeRequest(data, 0);
If you need a little more time between requests, then add the setTimeout
to the callback.
function makeRequest(arr, i) {
if (i < arr.length) {
request(arr[i].url, function() {
i++;
setTimeout(makeRequest, 1000, arr, i);
});
}
}
makeRequest(data, 0);
Upvotes: 3
Reputation: 142911
You can the offset the execution delay of each item by the index, like this:
data.forEach(function (result, i) {
setTimeout(function() {
url = data[i].url;
request(url);
}, i * 100);
});
This will make each iteration execute about 100 milliseconds after the previous one. You can change 100
to whatever number you like to change the delay.
Upvotes: 0
Reputation: 66921
data.forEach(function (result, i) {
url = data[i].url;
setTimeout(
function () {
request(url);
},
1000 * (i + 1) // where they will each progressively wait 1 sec more each
);
});
Upvotes: 5
Reputation: 23208
you can delay call using setTimeout. following code will insure that each request get called after timerMultiPlier
milliseconds from its previous request.
var timerMultiPlier = 1000;
data.forEach(function (result, i) {
setTimeout(function(){
url = data[i].url;
request(url);
}, timerMultiPlier*i );
});
Upvotes: 1