I have written a small helper function to make delayed sequential function execution easier.
We have the following case: we need to execute an array of functions. The second one has to execute after the first one finishes, the third after the second and so one. The scenario gets a bit more complicated when wee need some delay between functions. So we have to execute function 1, then after it finishes, wait for 200 ms, and execute function 2, then after another 500 ms execute function 3 and so on.
So the code is the following:
function runSequence(arr, scope, delay){
arr.push(function(){});
delay = delay || 0;
var i = 0,
len = arr.length;
for(;i < len-1; i++){
(function(index, thisObject){
arr[index] = function(){
var isFn = !!thisObject.call,
fn = isFn? thisObject : thisObject.fn,
fnScope = isFn? scope: thisObject.scope,
fnDelay = isFn? delay : thisObject.delay,
fnToExecute = function(){ fn.call(this); arr[index+1](); }
fnScope = fnScope || this;
fnDelay? setTimeout(function(){ fnToExecute.call(fnScope) }, fnDelay) : fnToExecute.call(fnScope);
}
})(i, arr[i]);
}
arr[0]();
}
We can do the following:
runSequence([
{ fn: function(){ console.log('executed immediately') }, delay: 0 },
{
fn: function(){ console.log('this was after 1500 ms, with scope: ', this.name) },
delay: 1500,
scope: {name: 'sequence running'}
},
{ fn: function(){ console.log('this was after 2s ') }, delay: 2000 }
], this)
/*
* The first and the last functions above are executed in the scope of the code executing the runSequence function
* The second function is instead called with the scope being the passed object, {name: 'sequence running'}
*/
or the following:
runSequence([
function(){ console.log('first after 200ms') },
function(){ console.log('yet another 200 ms') },
function(){ console.log('the last fn at 200ms') }
], this, 200)
/*
* A shorter form of the runSequence function call, with functions running at equal timeouts, in the passed 'this' scope
*/
This function can be useful when processing large amounts of data that would otherwise block the browser, or in cases when one would need to trigger ajax calls with a certain delay in between. I’m sure that there are other cases when this could prove useful.
In the case of processing large amounts of data, one could use this to fill up a (non-paginated) grid with data, in chunks of, say, 200 records.
Do you find this pattern useful?