v5.x
This commit is contained in:
		
							parent
							
								
									0cc859e3d0
								
							
						
					
					
						commit
						c543917f07
					
				
							
								
								
									
										89
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										89
									
								
								README.md
									
									
									
									
									
								
							@ -5,45 +5,45 @@ Analogous to `[].forEach`, but handles items asynchronously with a final callbac
 | 
			
		||||
 | 
			
		||||
This is the most essential piece of the [`ArrayAsync`](https://github.com/FuturesJS/ArrayAsync) package.
 | 
			
		||||
 | 
			
		||||
v3.x - Diet Cola Edition
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
As I do every few years, I decided to rewrite FuturesJS.
 | 
			
		||||
This year's remake is extremely lightweight.
 | 
			
		||||
v5.x
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
We jumped from 3.x to 5.x because I'm considering creating a backwards-and-forwards compatible 4.x that
 | 
			
		||||
uses AngularJS-style function introspection to allow for having the next param.
 | 
			
		||||
Straight up, that's probably a bad idea and waste of time so I hope I don't actually do it.
 | 
			
		||||
 | 
			
		||||
Usage
 | 
			
		||||
===
 | 
			
		||||
 | 
			
		||||
It's as simple as you could guess:
 | 
			
		||||
-----
 | 
			
		||||
 | 
			
		||||
```javascript
 | 
			
		||||
  // waits for one request to finish before beginning the next
 | 
			
		||||
  forEachAsync(['dogs', 'cats', 'octocats'], function (next, element, index, array) {
 | 
			
		||||
    getPics(element, next);
 | 
			
		||||
  
 | 
			
		||||
  // then after all of the elements have been handled
 | 
			
		||||
  // the final callback fires to let you know it's all done
 | 
			
		||||
  }).then(function () {
 | 
			
		||||
    console.log('All requests have finished');
 | 
			
		||||
  });
 | 
			
		||||
  // EXAMPLE ASYNC FUNCTION
 | 
			
		||||
 | 
			
		||||
  // where `getPics` might be an asynchronous web request such as this
 | 
			
		||||
  function getPics(animal, cb) {
 | 
			
		||||
    var flickerAPI = "http://api.flickr.com/services/feeds/photos_public.gne?jsoncallback=?";
 | 
			
		||||
    $.getJSON(
 | 
			
		||||
      flickerAPI
 | 
			
		||||
    , { tags: thing
 | 
			
		||||
      , tagmode: "any"
 | 
			
		||||
      , format: "json"
 | 
			
		||||
      , success: function (data) {
 | 
			
		||||
          console.log('teh animals:', data);
 | 
			
		||||
        }
 | 
			
		||||
      , complete: cb
 | 
			
		||||
      }
 | 
			
		||||
    );
 | 
			
		||||
  function getPicsAsync(animal) {
 | 
			
		||||
    var flickerApi = "http://api.flickr.com/services/feeds/photos_public.gne?tagmode=any&format=json&tags=" + animal;
 | 
			
		||||
 | 
			
		||||
    return requestAsync({ url: flickerApi });
 | 
			
		||||
  }
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```javascript
 | 
			
		||||
  forEachAsync(['dogs', 'cats', 'octocats'], function (element) {
 | 
			
		||||
    return getPicsAsync(element);
 | 
			
		||||
  }).then(function () {
 | 
			
		||||
    // then after all of the elements have been handled
 | 
			
		||||
    // the final callback fires to let you know it's all done
 | 
			
		||||
    console.log('All requests have finished');
 | 
			
		||||
  });
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Supplying your own Promises Implementation
 | 
			
		||||
 | 
			
		||||
If native ES6 promises are not available, then you should supply your own Promises/A+
 | 
			
		||||
implementation like so:
 | 
			
		||||
 | 
			
		||||
```javascript
 | 
			
		||||
  forEachAsync = forEachAsync.create(window.Promise || require('bluebird'));
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Browser Installation
 | 
			
		||||
===
 | 
			
		||||
@ -51,7 +51,7 @@ Browser Installation
 | 
			
		||||
You can install from bower:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
bower install forEachAsync
 | 
			
		||||
bower install --save forEachAsync@5.x
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Or download the raw file from <https://raw.github.com/FuturesJS/forEachAsync/master/forEachAsync.js>:
 | 
			
		||||
@ -71,35 +71,13 @@ wget https://raw.github.com/FuturesJS/forEachAsync/master/forEachAsync.js
 | 
			
		||||
}());
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Or you can build it alongside other libraries:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
npm install -g pakmanager
 | 
			
		||||
npm install forEachAsync --save
 | 
			
		||||
pakmanager -e browser build
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```html
 | 
			
		||||
<script src="pakmanaged.js"></script>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```javascript
 | 
			
		||||
(function () {
 | 
			
		||||
  'use strict';
 | 
			
		||||
 | 
			
		||||
  var forEachAsync = require('forEachAsync').forEachAsync
 | 
			
		||||
    ;
 | 
			
		||||
 | 
			
		||||
  // do stuff ...
 | 
			
		||||
}());
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Note**: If you need both 3.x/4.x and 5.x version of `forEachAsync` in the browser... good luck with that...
 | 
			
		||||
 | 
			
		||||
Node Installation
 | 
			
		||||
===
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
npm install --save forEachAsync@3.x
 | 
			
		||||
npm install --save forEachAsync@5.x
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
API
 | 
			
		||||
@ -111,7 +89,6 @@ Parameters
 | 
			
		||||
 | 
			
		||||
  * `array` Array of elements to iterate over
 | 
			
		||||
  * `callback` Function to execute for each element, takes 4 arguments
 | 
			
		||||
    * `next` the function to call when the current element has been dealt with
 | 
			
		||||
    * `element` a single element of the aforementioned array
 | 
			
		||||
    * `index` the index of the current element
 | 
			
		||||
    * `array` the same array mentioned above
 | 
			
		||||
 | 
			
		||||
@ -11,14 +11,16 @@ window.addEventListener('load', function () {
 | 
			
		||||
    ;
 | 
			
		||||
 | 
			
		||||
  log('i', 'item', 'ms');
 | 
			
		||||
  forEachAsync([2, 11, 37, 42], function (next, item, i) {
 | 
			
		||||
  forEachAsync([2, 11, 37, 42], function (item, i) {
 | 
			
		||||
    var ms = Math.floor(Math.random() * 1000)
 | 
			
		||||
      ;
 | 
			
		||||
 | 
			
		||||
    setTimeout(function () {
 | 
			
		||||
      log(i, item, ms);
 | 
			
		||||
      next();
 | 
			
		||||
    }, ms);
 | 
			
		||||
    return new Promise(function (resolve) {
 | 
			
		||||
      setTimeout(function () {
 | 
			
		||||
        log(i, item, ms);
 | 
			
		||||
        resolve();
 | 
			
		||||
      }, ms);
 | 
			
		||||
    });
 | 
			
		||||
  }).then(function () {
 | 
			
		||||
    log('All Done');
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
@ -1,20 +1,20 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
var fs = require('fs')
 | 
			
		||||
var PromiseA = require('bluebird')
 | 
			
		||||
  , fs = PromiseA.promisifyAll(require('fs'))
 | 
			
		||||
  , forEachAsync = require('foreachasync').forEachAsync
 | 
			
		||||
  , path = require('path')
 | 
			
		||||
  , dirpath = path.join(__dirname, 'testfiles')
 | 
			
		||||
  ;
 | 
			
		||||
 | 
			
		||||
fs.readdir(dirpath, function (err, nodes) {
 | 
			
		||||
  forEachAsync(nodes, function (next, node) {
 | 
			
		||||
  forEachAsync(nodes, function (node) {
 | 
			
		||||
    var filepath = path.join(dirpath, node)
 | 
			
		||||
      ;
 | 
			
		||||
 | 
			
		||||
    console.log(filepath);
 | 
			
		||||
    fs.readFile(filepath, null, function (err, contents) {
 | 
			
		||||
    return fs.readFileAsync(filepath, null).then(function (contents) {
 | 
			
		||||
      console.log(node, contents.length);
 | 
			
		||||
      next();
 | 
			
		||||
    });
 | 
			
		||||
  }).then(function () {
 | 
			
		||||
    console.log('All Done!');
 | 
			
		||||
 | 
			
		||||
@ -2,34 +2,89 @@
 | 
			
		||||
;(function (exports) {
 | 
			
		||||
  'use strict';
 | 
			
		||||
 | 
			
		||||
  function forEachAsync(arr, fn, thisArg) {
 | 
			
		||||
    var dones = []
 | 
			
		||||
      , index = -1
 | 
			
		||||
      ;
 | 
			
		||||
  var BREAK = {}
 | 
			
		||||
    , exp = {}
 | 
			
		||||
    ;
 | 
			
		||||
 | 
			
		||||
    function next(BREAK, result) {
 | 
			
		||||
      index += 1;
 | 
			
		||||
  function create(PromiseA) {
 | 
			
		||||
    PromiseA = PromiseA.Promise || PromiseA;
 | 
			
		||||
 | 
			
		||||
      if (index === arr.length || BREAK === forEachAsync.__BREAK) {
 | 
			
		||||
        dones.forEach(function (done) {
 | 
			
		||||
          done.call(thisArg, result);
 | 
			
		||||
 | 
			
		||||
    function forEachAsync(arr, fn, thisArg) {
 | 
			
		||||
      var result = PromiseA.resolve()
 | 
			
		||||
        ;
 | 
			
		||||
 | 
			
		||||
      arr.forEach(function (item, k) {
 | 
			
		||||
        result = result.then(function () {
 | 
			
		||||
 | 
			
		||||
          var ret
 | 
			
		||||
            ;
 | 
			
		||||
 | 
			
		||||
          if (thisArg) {
 | 
			
		||||
            ret = fn.call(thisArg, item, k, arr);
 | 
			
		||||
          } else {
 | 
			
		||||
            ret = result = fn(item, k, arr);
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          if (!ret.then) {
 | 
			
		||||
            ret = PromiseA.resolve(result);
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          ret.then(function (val) {
 | 
			
		||||
            if (val === forEachAsync.__BREAK) {
 | 
			
		||||
              return PromiseA.reject(new Error('break'));
 | 
			
		||||
              //throw new Error('break');
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return val;
 | 
			
		||||
          });
 | 
			
		||||
        });
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      fn.call(thisArg, next, arr[index], index, arr);
 | 
			
		||||
      result.catch(function (e) {
 | 
			
		||||
        if ('break' !== e.message) {
 | 
			
		||||
          throw e;
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setTimeout(next, 4);
 | 
			
		||||
    forEachAsync.__BREAK = BREAK;
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      then: function (_done) {
 | 
			
		||||
        dones.push(_done);
 | 
			
		||||
        return this;
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
    return forEachAsync;
 | 
			
		||||
  }
 | 
			
		||||
  forEachAsync.__BREAK = {};
 | 
			
		||||
 | 
			
		||||
  exports.forEachAsync = forEachAsync;
 | 
			
		||||
  /*
 | 
			
		||||
  exp = forEachAsync.forEachAsync = forEachAsync;
 | 
			
		||||
  exports = exports.forEachAsync = forEachAsync.forEachAsycn = forEachAsync;
 | 
			
		||||
  exports.create = forEachAsync.create = function () {};
 | 
			
		||||
  */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  try { 
 | 
			
		||||
   exp.forEachAsync = create(require('bluebird'));
 | 
			
		||||
  } catch(e) {
 | 
			
		||||
    if ('undefined' !== typeof PromiseA) {
 | 
			
		||||
      exp.forEachAsync = create(Promise);
 | 
			
		||||
    } else {
 | 
			
		||||
      try { 
 | 
			
		||||
       exp.forEachAsync = create(require('es6-promise'));
 | 
			
		||||
      } catch(e) {
 | 
			
		||||
        try { 
 | 
			
		||||
         exp.forEachAsync = create(require('rsvp'));
 | 
			
		||||
        } catch(e) {
 | 
			
		||||
          console.warning('forEachAsync needs requires a promise implementation and your environment does not provide one.'
 | 
			
		||||
            + '\nYou may provide your own by calling forEachAsync.create(Promise) with a PromiseA+ implementation'
 | 
			
		||||
          );
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  exports.forEachAsync = exp.forEachAsync.forEachAsync = exp.forEachAsync || function () {
 | 
			
		||||
    throw new Error("You did not supply a Promises/A+ implementation. See the warning above.");
 | 
			
		||||
  };
 | 
			
		||||
  exports.forEachAsync.create = create;
 | 
			
		||||
 | 
			
		||||
}('undefined' !== typeof exports && exports || new Function('return this')()));
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										11
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								package.json
									
									
									
									
									
								
							@ -1,7 +1,7 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "foreachasync",
 | 
			
		||||
  "version": "3.0.0",
 | 
			
		||||
  "description": "A node- and browser-ready async counterpart of Array.prototype.forEach",
 | 
			
		||||
  "version": "5.0.0",
 | 
			
		||||
  "description": "A node- and browser-ready async (now with promises) counterpart of Array.prototype.forEach",
 | 
			
		||||
  "homepage": "https://github.com/FuturesJS/forEachAsync",
 | 
			
		||||
  "main": "forEachAsync.js",
 | 
			
		||||
  "directories": {
 | 
			
		||||
@ -21,11 +21,18 @@
 | 
			
		||||
    "forEachAsync",
 | 
			
		||||
    "async",
 | 
			
		||||
    "futures",
 | 
			
		||||
    "promise",
 | 
			
		||||
    "promises",
 | 
			
		||||
    "each"
 | 
			
		||||
  ],
 | 
			
		||||
  "optionalDependencies": {
 | 
			
		||||
    "bluebird": "^2.5.3"
 | 
			
		||||
  },
 | 
			
		||||
  "author": "AJ ONeal <coolaj86@gmail.com> (http://coolaj86.com/)",
 | 
			
		||||
  "license": "Apache2",
 | 
			
		||||
  "bugs": {
 | 
			
		||||
    "url": "https://github.com/FuturesJS/forEachAsync/issues"
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										32
									
								
								test-bluebird.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								test-bluebird.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
			
		||||
(function () {
 | 
			
		||||
  "use strict";
 | 
			
		||||
 | 
			
		||||
  var PromiseA = require('bluebird')
 | 
			
		||||
    , forEachAsync = require('./forEachAsync').forEachAsync
 | 
			
		||||
    , context = {}
 | 
			
		||||
    ;
 | 
			
		||||
 | 
			
		||||
  forEachAsync([0, 500, 70, 200, 400, 100], function (element, i, arr) {
 | 
			
		||||
    // test that array order is as expected
 | 
			
		||||
    console.log(element, 'is element', i, 'of', arr.length);
 | 
			
		||||
 | 
			
		||||
    // test that thisness is applied
 | 
			
		||||
    this[element] = i;
 | 
			
		||||
 | 
			
		||||
    if (i > 2) {
 | 
			
		||||
      // test that synchronous callbacks don't mess things up
 | 
			
		||||
      return PromiseA.resolve();
 | 
			
		||||
    } else {
 | 
			
		||||
      // test asynchronous callbacks
 | 
			
		||||
      return new Promise(function (resolve/*, reject*/) {
 | 
			
		||||
        setTimeout(resolve, element);
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  }, context).then(function () {
 | 
			
		||||
    // test that thisness carried
 | 
			
		||||
    console.log('context', context);
 | 
			
		||||
  }).then(function () {
 | 
			
		||||
    // test then chaining
 | 
			
		||||
    console.log("now wasn't that nice?");
 | 
			
		||||
  });
 | 
			
		||||
}());
 | 
			
		||||
@ -1,10 +1,11 @@
 | 
			
		||||
(function () {
 | 
			
		||||
  "use strict";
 | 
			
		||||
 | 
			
		||||
  var forEachAsync = require('./forEachAsync').forEachAsync
 | 
			
		||||
  var forEachAsync = require('./forEachAsync').forEachAsync.create(Promise)
 | 
			
		||||
    , context = {}
 | 
			
		||||
    ;
 | 
			
		||||
 | 
			
		||||
  forEachAsync([0, 500, 70, 200, 400, 100], function (next, element, i, arr) {
 | 
			
		||||
  forEachAsync([0, 500, 70, 200, 400, 100], function (element, i, arr) {
 | 
			
		||||
    // test that array order is as expected
 | 
			
		||||
    console.log(element, 'is element', i, 'of', arr.length);
 | 
			
		||||
 | 
			
		||||
@ -13,17 +14,18 @@
 | 
			
		||||
 | 
			
		||||
    if (i > 2) {
 | 
			
		||||
      // test that synchronous callbacks don't mess things up
 | 
			
		||||
      next();
 | 
			
		||||
      return Promise.resolve();
 | 
			
		||||
    } else {
 | 
			
		||||
      // test asynchronous callbacks
 | 
			
		||||
      setTimeout(next, element);
 | 
			
		||||
      return new Promise(function (resolve/*, reject*/) {
 | 
			
		||||
        setTimeout(resolve, element);
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  }, {}).then(function () {
 | 
			
		||||
    // test that thisness carries
 | 
			
		||||
    console.log(this);
 | 
			
		||||
  }, context).then(function () {
 | 
			
		||||
    // test that thisness carried
 | 
			
		||||
    console.log('context', context);
 | 
			
		||||
  }).then(function () {
 | 
			
		||||
    // test then chaining
 | 
			
		||||
    console.log("now wasn't that nice?");
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
}());
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user