foreach.js 2.1 KB

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