/* JavaScript Sync/Async forEach - v0.1.2 - 1/10/2012 * http://github.com/cowboy/javascript-sync-async-foreach * Copyright (c) 2012 "Cowboy" Ben Alman; Licensed MIT */ (function(exports) { // Iterate synchronously or asynchronously. exports.forEach = function(arr, eachFn, doneFn) { var i = -1; // Resolve array length to a valid (ToUint32) number. var len = arr.length >>> 0; // This IIFE is called once now, and then again, by name, for each loop // iteration. (function next(result) { // This flag will be set to true if `this.async` is called inside the // eachFn` callback. var async; // Was false returned from the `eachFn` callback or passed to the // `this.async` done function? var abort = result === false; // Increment counter variable and skip any indices that don't exist. This // allows sparse arrays to be iterated. do { ++i; } while (!(i in arr) && i !== len); // Exit if result passed to `this.async` done function or returned from // the `eachFn` callback was false, or when done iterating. if (abort || i === len) { // If a `doneFn` callback was specified, invoke that now. Pass in a // boolean value representing "not aborted" state along with the array. if (doneFn) { doneFn(!abort, arr); } return; } // Invoke the `eachFn` callback, setting `this` inside the callback to a // custom object that contains one method, and passing in the array item, // index, and the array. result = eachFn.call({ // If `this.async` is called inside the `eachFn` callback, set the async // flag and return a function that can be used to continue iterating. async: function() { async = true; return next; } }, arr[i], i, arr); // If the async flag wasn't set, continue by calling `next` synchronously, // passing in the result of the `eachFn` callback. if (!async) { next(result); } }()); }; }(typeof exports === "object" && exports || this));