async forEach in JavaScript
After writing about Blocking vs Non-Blocking /me was stuck with making forEach of JS asynchronous as it was very much needed for an interesting challenge.
As I was stuck with a broken callback function trying to make async, took help from one of my hacker friends Mortchek to come up with a async loop, as below :
function asyncEach(array, iterator, delay) { void function iteration(index) { if (index === array.length) return iterator(array[index]) setTimeout(function () { iteration(index + 1) }, delay) }(0) }
Invocation : asyncEach([1, 2, 3], function (v) { console.log(v) }, 1000)
Well, yes there are many libs and others ways of doing this, but this is the best so far, do feel free to modify this for making is even better!
Update 0 : from RadekCZ
function asyncEach(array, fn, delay){ var i = 0; window.setTimeout(function iter(){ if(i===array.length){ return; } fn.call(array, array[i], i++); window.setTimeout(iter, delay); }, 0); }
The above function will create only one function for one forEach!
Update 1: from imbcmdth
I have written something similar for my ray tracer for loading and processing models.
Both methods presented so far have a critical failing: those style loops only run at a maximum of 250 iterations per second in modern HTML5 compliant browsers which specifies that the minimum interval between successive timeouts is 4ms regardless of the specified delay.
Performing those loops against a million element array is going to take quite a while!
Another thing missing is that you must have some form of a callback parameter that is called after the asynchronous loop is completed or you can't ever reliably do anything that depends on the results of the loop.
Instead, I propose an asynchronous loop like this:
function asyncEach(array, fn, progress, finished) { var i = 0, maxBurnTime = 100, // ms to run before yielding to user agent finishedFn = finished || progress, progressFn = (finishedFn === progress ? null : progress); function iter() { var startTime = Date.now(); while(i < array.length) { fn.call(array, array[i], i++); if(Date.now() - startTime > maxBurnTime) { if(progressFn) progressFn(i, array.length); return window.setTimeout(iter, 0); } } if(progressFn) progressFn(i, array.length); if(finishedFn) finishedFn(null, array); } window.setTimeout(iter, 0); }
Both callbacks are optional but very useful for large and slow processes or just to maintain a sequence of operations. I use node.js-style callback for finish(error, parameters) but you can use anything you'd like. The point is that by yielding only a few times a second, you can achieve almost native loop performance.
Here is an example use:
var b = 0; //Step 1: Generate 1 million numbers from 0 to 1 billion in steps of 1,000 //Step 2: Sum the square roots of all 1 million elements in the array asyncEach( new Array(1000000), function(e, i) { this[i] = 1000000000 - i * 1000; }, function(done, total) { console.log("Building Array: " + Math.floor( (done/total) * 100) + "%"); }, function(err, a) { asyncEach( a, function(e) { b += Math.sqrt(e); }, function(done, total) { console.log("Summing Square Roots: " + Math.floor( (done/total)* 100 ) + "%"); }, function(){ console.log('Answer: ' + b); }); });
If this wasn't executed asynchronously the user agent would be locked for several seconds.
Recent blog posts
- watir-webdriver web inspector
- gem list to gemfile
- Packing ruby2.0 on debian.
- Made it into The Guinness Book!
- to_h in ruby 2.0
- Filter elements by pattern jQuery.
- Better HTML password fields for mobile ?
- Grayscale image when user offline
- nth-child CSS pseudo-class Christmas colors
- EventEmitter in nodejs