ba-foreach.js 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. /* JavaScript Sync/Async forEach - v0.1.2 - 1/10/2012
  2. * http://github.com/cowboy/javascript-sync-async-foreach
  3. * Copyright (c) 2012 "Cowboy" Ben Alman; Licensed MIT */
  4. (function(exports) {
  5. // Iterate synchronously or asynchronously.
  6. exports.forEach = function(arr, eachFn, doneFn) {
  7. var i = -1;
  8. // Resolve array length to a valid (ToUint32) number.
  9. var len = arr.length >>> 0;
  10. // This IIFE is called once now, and then again, by name, for each loop
  11. // iteration.
  12. (function next(result) {
  13. // This flag will be set to true if `this.async` is called inside the
  14. // eachFn` callback.
  15. var async;
  16. // Was false returned from the `eachFn` callback or passed to the
  17. // `this.async` done function?
  18. var abort = result === false;
  19. // Increment counter variable and skip any indices that don't exist. This
  20. // allows sparse arrays to be iterated.
  21. do { ++i; } while (!(i in arr) && i !== len);
  22. // Exit if result passed to `this.async` done function or returned from
  23. // the `eachFn` callback was false, or when done iterating.
  24. if (abort || i === len) {
  25. // If a `doneFn` callback was specified, invoke that now. Pass in a
  26. // boolean value representing "not aborted" state along with the array.
  27. if (doneFn) {
  28. doneFn(!abort, arr);
  29. }
  30. return;
  31. }
  32. // Invoke the `eachFn` callback, setting `this` inside the callback to a
  33. // custom object that contains one method, and passing in the array item,
  34. // index, and the array.
  35. result = eachFn.call({
  36. // If `this.async` is called inside the `eachFn` callback, set the async
  37. // flag and return a function that can be used to continue iterating.
  38. async: function() {
  39. async = true;
  40. return next;
  41. }
  42. }, arr[i], i, arr);
  43. // If the async flag wasn't set, continue by calling `next` synchronously,
  44. // passing in the result of the `eachFn` callback.
  45. if (!async) {
  46. next(result);
  47. }
  48. }());
  49. };
  50. }(typeof exports === "object" && exports || this));