Compare commits

..

33 Commits

Author SHA1 Message Date
AJ ONeal e534d3a4b3 v5.1.3: remove deps, update link 2019-04-05 12:53:27 -06:00
AJ ONeal 7ba1195ac5 update README.md 2018-03-28 00:24:32 -06:00
AJ ONeal 34d8d7bbc5 v5.1.2 2018-03-27 23:52:32 -06:00
AJ ONeal 7fa166802a update URLs 2018-03-27 23:52:12 -06:00
AJ ONeal 0022ba5abe v5.1.1 2018-03-27 23:50:55 -06:00
AJ ONeal 2f6f9d5e8e update URLs 2018-03-27 23:50:34 -06:00
AJ ONeal 812950328d v5.1.0 2018-03-27 23:41:41 -06:00
AJ ONeal ba81917d4f version bump 2015-01-07 00:55:24 -07:00
AJ ONeal c8875d8d40 promise correct result 2015-01-07 00:55:18 -07:00
AJ ONeal f761f9215c fix #1 check for null / undefined result 2015-01-07 00:53:45 -07:00
AJ ONeal 7218a53487 version bump 2015-01-05 23:22:06 -07:00
AJ ONeal 5689274eb8 console.warning -> console.warn 2015-01-05 23:20:57 -07:00
AJ ONeal 676159ba62 typo fix for native Promise implementation 2015-01-05 23:20:29 -07:00
AJ ONeal 70eda0ad55 fixed order bug 2015-01-02 18:39:27 -07:00
AJ ONeal 8daeae0e1d v5.x 2015-01-02 18:10:44 -07:00
AJ ONeal 1fbc93a178 v5.x 2015-01-02 18:09:56 -07:00
AJ ONeal c543917f07 v5.x 2015-01-02 18:08:02 -07:00
AJ ONeal 9054f65649 added screencast 2014-01-22 16:20:37 -07:00
AJ ONeal a60f4c3058 added reference to forAllAsync, lateral, and join 2014-01-22 16:19:21 -07:00
AJ ONeal 0cc859e3d0 added build script 2014-01-22 13:43:49 -07:00
AJ ONeal d7b24ee975 ignore more stuff 2014-01-22 13:39:59 -07:00
AJ ONeal 50fe98e94d added node example 2014-01-22 13:37:28 -07:00
AJ ONeal 527d76dbd9 added browser example 2014-01-22 13:17:04 -07:00
AJ ONeal 155d2c416c name is now lowercase 2014-01-22 12:46:54 -07:00
AJ ONeal 802e87d117 ignore bower_components 2014-01-22 12:46:07 -07:00
AJ ONeal 8b304f984e remove note about 'beta' version, link to someAsync 2014-01-22 12:45:44 -07:00
AJ ONeal 01af95b289 updated metadata 2014-01-13 16:07:10 -07:00
AJ ONeal a748861ed8 promoted to stable 2014-01-13 16:06:56 -07:00
AJ ONeal 592ac5cb53 added leading semicolon 2014-01-13 16:06:43 -07:00
AJ ONeal 7b6938181c add bower instructions 2014-01-12 00:48:18 -07:00
AJ ONeal e611d3f769 added bower.json 2014-01-12 00:38:14 -07:00
AJ ONeal 6bdf214962 updated version number 2014-01-12 00:33:41 -07:00
AJ ONeal ea52246ee7 moved important part of example up front 2013-08-06 12:23:16 -07:00
20 changed files with 370 additions and 132 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
bower_components

104
README.md
View File

@ -1,99 +1,92 @@
forEachAsync forEachAsync.js
=== ===
As I do every few years, I decided to rewrite FuturesJS. | A [Root](https://rootprojects.org) project
This year's remake is extremely lightweight.
v3.x - Diet Cola Edition
(published on npm as beta, so you must use the @3.x - and don't worry, v2.x is still supported)
Analogous to `[].forEach`, but handles items asynchronously with a final callback passed to `then`. Analogous to `[].forEach`, but handles items asynchronously with a final callback passed to `then`.
This is the most essential piece of the [`ArrayAsync`](https://github.com/FuturesJS/ArrayAsync) package. This is the most essential piece of the [`ArrayAsync`](https://github.com/FuturesJS/ArrayAsync) package.
Usage For cases where you want to loop through batches of items at once (as opposed to strictly one-by-one as forEachAsync does), check out [`forAllAsync`](https://github.com/FuturesJS/forAllAsync) and [`lateral`](https://github.com/FuturesJS/lateral).
===
It's as simple as you could guess: For cases where you want to loop through all items at once and we able to know when they're all done see [`join`](https://github.com/FuturesJS/join)
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.
Screencast
---
<https://youtu.be/O7egvEz4scA>
Usage
-----
```javascript ```javascript
// an asynchronous web request // EXAMPLE ASYNC FUNCTION
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
}
);
}
// waits for one request to finish before beginning the next function getPicsAsync(animal) {
forEachAsync(['dogs', 'cats', 'octocats'], function (next, element, index, array) { var flickerApi = "http://api.flickr.com/services/feeds/photos_public.gne?tagmode=any&format=json&tags=" + animal;
getPics(element, next);
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 // then after all of the elements have been handled
// the final callback fires to let you know it's all done // the final callback fires to let you know it's all done
}).then(function () {
console.log('All requests have finished'); 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 Browser Installation
=== ===
You can download and include `forEachAsync.js`: You can install from bower:
```html
<script src="https://raw.github.com/FuturesJS/forEachAsync/master/forEachAsync.js"></script>
```
```javascript
(function () {
'use strict';
var forEachAsync = window.forEachAsync
;
// do stuff ...
}());
```
Or you can build it alongside other libraries:
```bash ```bash
npm install -g pakmanager bower install --save forEachAsync@5.x
npm install forEachAsync@3.x --save
pakmanager -e browser build
``` ```
```html Or download the raw file from <https://git.coolaj86.com/coolaj86/foreachasync.js/raw/branch/master/foreachasync.js>:
<script src="pakmanaged.js"></script>
```bash
wget https://git.coolaj86.com/coolaj86/foreachasync.js/raw/branch/master/foreachasync.js
``` ```
```javascript ```javascript
(function () { (function () {
'use strict'; 'use strict';
var forEachAsync = require('forEachAsync').forEachAsync var forEachAsync = window.forEachAsync;
;
// do stuff ... // 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 Node Installation
=== ===
```bash ```bash
npm install --save forEachAsync@3.x npm install --save foreachasync@5.x
``` ```
API API
@ -105,7 +98,6 @@ Parameters
* `array` Array of elements to iterate over * `array` Array of elements to iterate over
* `callback` Function to execute for each element, takes 4 arguments * `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 * `element` a single element of the aforementioned array
* `index` the index of the current element * `index` the index of the current element
* `array` the same array mentioned above * `array` the same array mentioned above
@ -125,4 +117,4 @@ Internal API
This is used internally for the purposes of the `ArrayAsync` library. This is used internally for the purposes of the `ArrayAsync` library.
Please don't `break` stuff; use `someAsync` or `everyAsync` instead. Please don't `break` stuff; use [`ArrayAsync`](https://github.com/FuturesJS/ArrayAsync)`.someAsync` or [`ArrayAsync`](https://github.com/FuturesJS/ArrayAsync)`.everyAsync` instead.

27
bower.json Normal file
View File

@ -0,0 +1,27 @@
{
"name": "forEachAsync",
"main": "forEachAsync.js",
"version": "3.0.0",
"homepage": "https://github.com/FuturesJS/forEachAsync",
"authors": [
"AJ ONeal <coolaj86@gmail.com>"
],
"description": "A node- and browser-ready async counterpart of Array.prototype.forEach",
"keywords": [
"futuresjs",
"forEachAsync",
"forEach",
"for",
"async",
"each",
"asynchronous"
],
"license": "Apache-v2",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
]
}

1
examples/browser/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.html

3
examples/browser/build.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/bash
bower install forEachAsync
jade *.jade

View File

@ -0,0 +1,21 @@
window.addEventListener('load', function () {
'use strict';
function log() {
document.querySelector('#foreach-console').innerHTML +=
'\n' + Array.prototype.join.call(arguments, ' | ');
console.log.apply(console, arguments);
}
log('i', 'item', 'ms');
[2, 11, 37, 42].forEach(function (item, i) {
var ms = Math.floor(Math.random() * 1000)
;
setTimeout(function () {
log(i, item, ms);
}, ms);
});
log('All Done');
});

View File

@ -0,0 +1,27 @@
window.addEventListener('load', function () {
'use strict';
function log() {
document.querySelector('#foreachasync-console').innerHTML +=
'\n' + Array.prototype.join.call(arguments, ' | ');
console.log.apply(console, arguments);
}
var forEachAsync = window.forEachAsync
;
log('i', 'item', 'ms');
forEachAsync([2, 11, 37, 42], function (item, i) {
var ms = Math.floor(Math.random() * 1000)
;
return new Promise(function (resolve) {
setTimeout(function () {
log(i, item, ms);
resolve();
}, ms);
});
}).then(function () {
log('All Done');
});
});

View File

@ -0,0 +1,14 @@
doctype html
html
head
title forEachAsync example
script(src="bower_components/forEachAsync/forEachAsync.js")
script(src="foreach-settimeout.js")
script(src="foreachasync-settimeout.js")
body
h1 Array.prototype.forEach
code
pre#foreach-console
h1 forEachAsync
code
pre#foreachasync-console

2
examples/node/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
node_modules
testfiles

View File

@ -0,0 +1,20 @@
'use strict';
var fs = require('fs')
, path = require('path')
, dirpath = path.join(__dirname, 'testfiles')
;
fs.readdir(dirpath, function (err, nodes) {
nodes.forEach(function (node) {
var filepath = path.join(dirpath, node)
;
console.log(filepath);
fs.readFile(filepath, null, function (err, contents) {
console.log(node, contents.length);
});
});
console.log('All Done');
});

View File

@ -0,0 +1,22 @@
'use strict';
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 (node) {
var filepath = path.join(dirpath, node)
;
console.log(filepath);
return fs.readFileAsync(filepath, null).then(function (contents) {
console.log(node, contents.length);
});
}).then(function () {
console.log('All Done!');
});
});

View File

@ -0,0 +1,8 @@
mkdir -p testfiles
touch ./testfiles/0b.bin
dd bs=1m count=1 if=/dev/zero of=./testfiles/1mb.bin
dd bs=1k count=64 if=/dev/zero of=./testfiles/64kb.bin
dd bs=1k count=96 if=/dev/zero of=./testfiles/96kb.bin
dd bs=1k count=1 if=/dev/zero of=./testfiles/1kb.bin
# this will copy one block which could be between 512b and 4k (or more)
dd bs=1b count=1 if=/dev/zero of=./testfiles/block.bin

0
examples/node/node_modules/.gitkeep generated vendored Normal file
View File

View File

@ -1,35 +0,0 @@
/*jshint -W054 */
(function (exports) {
"use strict";
function forEachAsync(arr, fn, thisArg) {
var dones = []
, index = -1
;
function next(BREAK, result) {
index += 1;
if (index === arr.length || BREAK === forEachAsync.__BREAK) {
dones.forEach(function (done) {
done.call(thisArg, result);
});
return;
}
fn.call(thisArg, next, arr[index], index, arr);
}
setTimeout(next, 4);
return {
then: function (_done) {
dones.push(_done);
return this;
}
};
}
forEachAsync.__BREAK = {};
exports.forEachAsync = forEachAsync;
}('undefined' !== typeof exports && exports || new Function('return this')()));

79
foreachasync.js Normal file
View File

@ -0,0 +1,79 @@
/*jshint -W054 */
;(function (exports) {
'use strict';
var BREAK = {};
var exp = {};
function create(PromiseA) {
PromiseA = PromiseA.Promise || PromiseA;
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 || !ret.then) {
ret = PromiseA.resolve(ret);
}
return ret.then(function (val) {
if (val === forEachAsync.__BREAK) {
return PromiseA.reject(new Error('break'));
//throw new Error('break');
}
return val;
});
});
});
result.catch(function (e) {
if ('break' !== e.message) {
throw e;
}
});
return result;
}
forEachAsync.__BREAK = BREAK;
return forEachAsync;
}
/*
exp = forEachAsync.forEachAsync = forEachAsync;
exports = exports.forEachAsync = forEachAsync.forEachAsycn = forEachAsync;
exports.create = forEachAsync.create = function () {};
*/
/* globals Promise */
if ('undefined' !== typeof Promise) {
exp.forEachAsync = create(Promise);
}
else {
try {
exp.forEachAsync = create(require('bluebird'));
} catch(e) {
console.warn("This version of node doesn't support promises. Please `npm install --save bluebird` in your project.");
}
}
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 || window));

5
package-lock.json generated Normal file
View File

@ -0,0 +1,5 @@
{
"name": "foreachasync",
"version": "5.1.3",
"lockfileVersion": 1
}

View File

@ -1,8 +1,10 @@
{ {
"name": "forEachAsync", "name": "foreachasync",
"version": "3.0.0-rc1", "version": "5.1.3",
"description": "A node- and browser-ready async counterpart of Array.prototype.forEach", "description": "A node- and browser-ready async (now with promises) counterpart of Array.prototype.forEach",
"main": "forEachAsync.js", "homepage": "https://git.coolaj86.com/coolaj86/foreachasync.js",
"main": "foreachasync.js",
"files": [],
"directories": { "directories": {
"test": "test" "test": "test"
}, },
@ -11,20 +13,26 @@
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git://github.com/FuturesJS/forEachAsync.git" "url": "https://git.coolaj86.com/coolaj86/foreachasync.js.git"
}, },
"keywords": [ "keywords": [
"futuresjs",
"forEach", "forEach",
"for", "for",
"forEachAsync", "forEachAsync",
"async", "async",
"futures", "futures",
"futuresjs", "promise",
"promises",
"each" "each"
], ],
"author": "AJ ONeal <coolaj86@gmail.com> (http://coolaj86.info/)", "trulyOptionalDependencies": {
"license": "Apache2", "bluebird": "^3.5.1"
},
"author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)",
"license": "(MIT OR Apache-2.0)",
"bugs": { "bugs": {
"url": "https://github.com/FuturesJS/forEachAsync/issues" "url": "https://git.coolaj86.com/coolaj86/foreachasync.js/issues"
} },
"dependencies": {}
} }

37
test-bluebird.js Normal file
View File

@ -0,0 +1,37 @@
(function () {
"use strict";
var PromiseA = require('bluebird');
var forEachAsync = require('./forEachAsync').forEachAsync;
var context = {};
forEachAsync([0, 500, 70, 200, 400, 100], function (element, i, arr) {
console.log(i, '/', arr.length, 'began');
var result;
// test that thisness is applied
this[element] = i;
if (i % 2) {
// test that synchronous callbacks don't mess things up
result = PromiseA.resolve();
} else {
// test asynchronous callbacks
result = new PromiseA(function (resolve/*, reject*/) {
setTimeout(resolve, element);
});
}
return result.then(function () {
// test that array order is as expected
console.log(i, '/', arr.length, 'complete');
});
}, context).then(function () {
// test that thisness carried
console.log('context', context);
}).then(function () {
// test then chaining
console.log("now wasn't that nice?");
});
}());

35
test-native.js Normal file
View File

@ -0,0 +1,35 @@
(function () {
"use strict";
/* globals Promise */
var forEachAsync = require('./forEachAsync').forEachAsync.create(Promise);
var context = {};
forEachAsync([0, 500, 70, 200, 400, 100], function (element, i, arr) {
var p;
// test that thisness is applied
this[element] = i;
if (i % 2) {
// test that synchronous callbacks don't mess things up
p = Promise.resolve();
} else {
// test asynchronous callbacks
p = new Promise(function (resolve/*, reject*/) {
setTimeout(resolve, element);
});
}
return p.then(function () {
// test that array order is as expected
console.log(element, 'is element', i, 'of', arr.length);
});
}, context).then(function () {
// test that thisness carried
console.log('context', context);
}).then(function () {
// test then chaining
console.log("now wasn't that nice?");
});
}());

29
test.js
View File

@ -1,29 +0,0 @@
(function () {
"use strict";
var forEachAsync = require('./forEachAsync').forEachAsync
;
forEachAsync([0, 500, 70, 200, 400, 100], function (next, 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
next();
} else {
// test asynchronous callbacks
setTimeout(next, element);
}
}, {}).then(function () {
// test that thisness carries
console.log(this);
}).then(function () {
// test then chaining
console.log("now wasn't that nice?");
});
}());