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
			| 
								 
											4 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/>
							 |