Suppose you have an asynchronous function in Javascript and you want to limit the maximum calls get executed at once and queued all others. This article explains how to implement it in simple way. Let's start with queue like structure:
var MAX_CONCURRENCY_LIMIT = 3;
var IDLE_DELAY = 500;
var tasks = {
queue : [],
totalActive :0,
add : function(item){
if (!item || item.length == 0){
return;
}
var q = this.queue;
if (q.indexOf(item) == -1)
q.push(item);
},
done : function(item){
this.totalActive--;
},
getNext : function(){
this.totalActive++;
//It will remove the returned item from queue automatically
return this.queue.shift();
},
isPending : function(){
return this.queue.length > 0;
}
};
MAX_CONCURRENCY_LIMIT is constant defines maximum number of tasks executing at the same time(parallel limit).
IDLE_DELAY is delay in millisecond to check if any task in queue.
To manage the concurrency and execute the function, here is the code
function runTask(){
if (tasks.isPending() && tasks.totalActive < MAX_CONCURRENCY_LIMIT){
var item = tasks.getNext();
console.log('Processing ' + item + ' Total Active Items ' + tasks.totalActive);
myTask(item);
runTask();
}
else if(tasks.totalActive >= MAX_CONCURRENCY_LIMIT){
console.log('Hold State');
setTimeout(function(){ runTask(); }, IDLE_DELAY);
}
else{
setTimeout(function(){ runTask(); }, IDLE_DELAY);
}
}
runTask();
For simplicity, let's take following asynchronous function.
function myTask(item){
setTimeout(function(){
console.log(item + ' completed.');
tasks.done(item);
}, 500);
}
To test the parallel limit, let's use following code:
for(var i=1;i<=10;i++){
tasks.add('Item: ' + i);
}
Output:
Processing Item: 1 Total Active Items 1 Processing Item: 2 Total Active Items 2 Processing Item: 3 Total Active Items 3 Hold State Item: 1 completed. Item: 2 completed. Item: 3 completed. Processing Item: 4 Total Active Items 1 Processing Item: 5 Total Active Items 2 Processing Item: 6 Total Active Items 3 Hold State Item: 4 completed. Item: 5 completed. Item: 6 completed. Processing Item: 7 Total Active Items 1 Processing Item: 8 Total Active Items 2 Processing Item: 9 Total Active Items 3 Hold State Item: 7 completed. Item: 8 completed. Item: 9 completed. Processing Item: 10 Total Active Items 1 Item: 10 completed.
You can see 3-3 items are queued and processed. Once it reaches max limit then hold state comes.
Now let's do some more fun for testing
function myTask(item){
setTimeout(function(){
console.log(item + ' completed.');
tasks.done(item);
}, Math.random()*1000);
}
now this function takes randomize time to get completed.
Outout:Processing Item: 1 Total Active Items 1 Processing Item: 2 Total Active Items 2 Processing Item: 3 Total Active Items 3 Hold State Item: 1 completed. Processing Item: 4 Total Active Items 3 Hold State Item: 2 completed. Item: 4 completed. Item: 3 completed. Processing Item: 5 Total Active Items 1 Processing Item: 6 Total Active Items 2 Processing Item: 7 Total Active Items 3 Hold State Item: 7 completed. Processing Item: 8 Total Active Items 3 Hold State Item: 5 completed. Item: 6 completed. Processing Item: 9 Total Active Items 2 Processing Item: 10 Total Active Items 3 Hold State Item: 8 completed. Item: 9 completed. Item: 10 completed.
You can see if any item is completed, another item is picked from queue for processing. On max limit, hold state comes. You can customize it according to your requirement.
Hope, it helps. Enjoy Javascript !!