You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
196 lines
4.9 KiB
196 lines
4.9 KiB
2 years ago
|
# JavaScript Sync/Async forEach
|
||
|
|
||
|
An optionally-asynchronous forEach with an interesting interface.
|
||
|
|
||
|
## Getting Started
|
||
|
|
||
|
This code should work just fine in Node.js:
|
||
|
|
||
|
First, install the module with: `npm install async-foreach`
|
||
|
|
||
|
```javascript
|
||
|
var forEach = require('async-foreach').forEach;
|
||
|
forEach(["a", "b", "c"], function(item, index, arr) {
|
||
|
console.log("each", item, index, arr);
|
||
|
});
|
||
|
// logs:
|
||
|
// each a 0 ["a", "b", "c"]
|
||
|
// each b 1 ["a", "b", "c"]
|
||
|
// each c 2 ["a", "b", "c"]
|
||
|
```
|
||
|
|
||
|
Or in the browser:
|
||
|
|
||
|
```html
|
||
|
<script src="dist/ba-foreach.min.js"></script>
|
||
|
<script>
|
||
|
forEach(["a", "b", "c"], function(item, index, arr) {
|
||
|
console.log("each", item, index, arr);
|
||
|
});
|
||
|
// logs:
|
||
|
// each a 0 ["a", "b", "c"]
|
||
|
// each b 1 ["a", "b", "c"]
|
||
|
// each c 2 ["a", "b", "c"]
|
||
|
</script>
|
||
|
```
|
||
|
|
||
|
In the browser, you can attach the forEach method to any object.
|
||
|
|
||
|
```html
|
||
|
<script>
|
||
|
this.exports = Bocoup.utils;
|
||
|
</script>
|
||
|
<script src="dist/ba-foreach.min.js"></script>
|
||
|
<script>
|
||
|
Bocoup.utils.forEach(["a", "b", "c"], function(item, index, arr) {
|
||
|
console.log("each", item, index, arr);
|
||
|
});
|
||
|
// logs:
|
||
|
// each a 0 ["a", "b", "c"]
|
||
|
// each b 1 ["a", "b", "c"]
|
||
|
// each c 2 ["a", "b", "c"]
|
||
|
</script>
|
||
|
```
|
||
|
|
||
|
## The General Idea (Why I thought this was worth sharing)
|
||
|
|
||
|
The idea is to allow the callback to decide _at runtime_ whether the loop will be synchronous or asynchronous. By using `this` in a creative way (in situations where that value isn't already spoken for), an entire control API can be offered without over-complicating function signatures.
|
||
|
|
||
|
```javascript
|
||
|
forEach(arr, function(item, index) {
|
||
|
// Synchronous.
|
||
|
});
|
||
|
|
||
|
forEach(arr, function(item, index) {
|
||
|
// Only when `this.async` is called does iteration becomes asynchronous. The
|
||
|
// loop won't be continued until the `done` function is executed.
|
||
|
var done = this.async();
|
||
|
// Continue in one second.
|
||
|
setTimeout(done, 1000);
|
||
|
});
|
||
|
|
||
|
forEach(arr, function(item, index) {
|
||
|
// Break out of synchronous iteration early by returning false.
|
||
|
return index !== 1;
|
||
|
});
|
||
|
|
||
|
forEach(arr, function(item, index) {
|
||
|
// Break out of asynchronous iteration early...
|
||
|
var done = this.async();
|
||
|
// ...by passing false to the done function.
|
||
|
setTimeout(function() {
|
||
|
done(index !== 1);
|
||
|
});
|
||
|
});
|
||
|
```
|
||
|
|
||
|
## Examples
|
||
|
See the unit tests for more examples.
|
||
|
|
||
|
```javascript
|
||
|
// Generic "done" callback.
|
||
|
function allDone(notAborted, arr) {
|
||
|
console.log("done", notAborted, arr);
|
||
|
}
|
||
|
|
||
|
// Synchronous.
|
||
|
forEach(["a", "b", "c"], function(item, index, arr) {
|
||
|
console.log("each", item, index, arr);
|
||
|
}, allDone);
|
||
|
// logs:
|
||
|
// each a 0 ["a", "b", "c"]
|
||
|
// each b 1 ["a", "b", "c"]
|
||
|
// each c 2 ["a", "b", "c"]
|
||
|
// done true ["a", "b", "c"]
|
||
|
|
||
|
// Synchronous with early abort.
|
||
|
forEach(["a", "b", "c"], function(item, index, arr) {
|
||
|
console.log("each", item, index, arr);
|
||
|
if (item === "b") { return false; }
|
||
|
}, allDone);
|
||
|
// logs:
|
||
|
// each a 0 ["a", "b", "c"]
|
||
|
// each b 1 ["a", "b", "c"]
|
||
|
// done false ["a", "b", "c"]
|
||
|
|
||
|
// Asynchronous.
|
||
|
forEach(["a", "b", "c"], function(item, index, arr) {
|
||
|
console.log("each", item, index, arr);
|
||
|
var done = this.async();
|
||
|
setTimeout(function() {
|
||
|
done();
|
||
|
}, 500);
|
||
|
}, allDone);
|
||
|
// logs:
|
||
|
// each a 0 ["a", "b", "c"]
|
||
|
// each b 1 ["a", "b", "c"]
|
||
|
// each c 2 ["a", "b", "c"]
|
||
|
// done true ["a", "b", "c"]
|
||
|
|
||
|
// Asynchronous with early abort.
|
||
|
forEach(["a", "b", "c"], function(item, index, arr) {
|
||
|
console.log("each", item, index, arr);
|
||
|
var done = this.async();
|
||
|
setTimeout(function() {
|
||
|
done(item !== "b");
|
||
|
}, 500);
|
||
|
}, allDone);
|
||
|
// logs:
|
||
|
// each a 0 ["a", "b", "c"]
|
||
|
// each b 1 ["a", "b", "c"]
|
||
|
// done false ["a", "b", "c"]
|
||
|
|
||
|
// Not actually asynchronous.
|
||
|
forEach(["a", "b", "c"], function(item, index, arr) {
|
||
|
console.log("each", item, index, arr);
|
||
|
var done = this.async()
|
||
|
done();
|
||
|
}, allDone);
|
||
|
// logs:
|
||
|
// each a 0 ["a", "b", "c"]
|
||
|
// each b 1 ["a", "b", "c"]
|
||
|
// each c 2 ["a", "b", "c"]
|
||
|
// done true ["a", "b", "c"]
|
||
|
|
||
|
// Not actually asynchronous with early abort.
|
||
|
forEach(["a", "b", "c"], function(item, index, arr) {
|
||
|
console.log("each", item, index, arr);
|
||
|
var done = this.async();
|
||
|
done(item !== "b");
|
||
|
}, allDone);
|
||
|
// logs:
|
||
|
// each a 0 ["a", "b", "c"]
|
||
|
// each b 1 ["a", "b", "c"]
|
||
|
// done false ["a", "b", "c"]
|
||
|
```
|
||
|
|
||
|
## Contributing
|
||
|
In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [grunt](https://github.com/cowboy/grunt).
|
||
|
|
||
|
_Also, please don't edit files in the "dist" subdirectory as they are generated via grunt. You'll find source code in the "lib" subdirectory!_
|
||
|
|
||
|
## Release History
|
||
|
|
||
|
04/29/2013
|
||
|
v0.1.3
|
||
|
Removed hard Node.js version dependency.
|
||
|
|
||
|
11/17/2011
|
||
|
v0.1.2
|
||
|
Adding sparse array support.
|
||
|
Invalid length properties are now sanitized.
|
||
|
This closes issue #1 (like a boss).
|
||
|
|
||
|
11/11/2011
|
||
|
v0.1.1
|
||
|
Refactored code to be much simpler. Yay for unit tests!
|
||
|
|
||
|
11/11/2011
|
||
|
v0.1.0
|
||
|
Initial Release.
|
||
|
|
||
|
## License
|
||
|
Copyright (c) 2012 "Cowboy" Ben Alman
|
||
|
Licensed under the MIT license.
|
||
|
<http://benalman.com/about/license/>
|