1 | # JavaScript Sync/Async forEach
|
2 |
|
3 | An optionally-asynchronous forEach with an interesting interface.
|
4 |
|
5 | ## Getting Started
|
6 |
|
7 | This code should work just fine in Node.js:
|
8 |
|
9 | First, install the module with: `npm install async-foreach`
|
10 |
|
11 | ```javascript
|
12 | var forEach = require('async-foreach').forEach;
|
13 | forEach(["a", "b", "c"], function(item, index, arr) {
|
14 | console.log("each", item, index, arr);
|
15 | });
|
16 | // logs:
|
17 | // each a 0 ["a", "b", "c"]
|
18 | // each b 1 ["a", "b", "c"]
|
19 | // each c 2 ["a", "b", "c"]
|
20 | ```
|
21 |
|
22 | Or in the browser:
|
23 |
|
24 | ```html
|
25 | <script src="dist/ba-foreach.min.js"></script>
|
26 | <script>
|
27 | forEach(["a", "b", "c"], function(item, index, arr) {
|
28 | console.log("each", item, index, arr);
|
29 | });
|
30 | // logs:
|
31 | // each a 0 ["a", "b", "c"]
|
32 | // each b 1 ["a", "b", "c"]
|
33 | // each c 2 ["a", "b", "c"]
|
34 | </script>
|
35 | ```
|
36 |
|
37 | In the browser, you can attach the forEach method to any object.
|
38 |
|
39 | ```html
|
40 | <script>
|
41 | this.exports = Bocoup.utils;
|
42 | </script>
|
43 | <script src="dist/ba-foreach.min.js"></script>
|
44 | <script>
|
45 | Bocoup.utils.forEach(["a", "b", "c"], function(item, index, arr) {
|
46 | console.log("each", item, index, arr);
|
47 | });
|
48 | // logs:
|
49 | // each a 0 ["a", "b", "c"]
|
50 | // each b 1 ["a", "b", "c"]
|
51 | // each c 2 ["a", "b", "c"]
|
52 | </script>
|
53 | ```
|
54 |
|
55 | ## The General Idea (Why I thought this was worth sharing)
|
56 |
|
57 | 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.
|
58 |
|
59 | ```javascript
|
60 | forEach(arr, function(item, index) {
|
61 | // Synchronous.
|
62 | });
|
63 |
|
64 | forEach(arr, function(item, index) {
|
65 | // Only when `this.async` is called does iteration becomes asynchronous. The
|
66 | // loop won't be continued until the `done` function is executed.
|
67 | var done = this.async();
|
68 | // Continue in one second.
|
69 | setTimeout(done, 1000);
|
70 | });
|
71 |
|
72 | forEach(arr, function(item, index) {
|
73 | // Break out of synchronous iteration early by returning false.
|
74 | return index !== 1;
|
75 | });
|
76 |
|
77 | forEach(arr, function(item, index) {
|
78 | // Break out of asynchronous iteration early...
|
79 | var done = this.async();
|
80 | // ...by passing false to the done function.
|
81 | setTimeout(function() {
|
82 | done(index !== 1);
|
83 | });
|
84 | });
|
85 | ```
|
86 |
|
87 | ## Examples
|
88 | See the unit tests for more examples.
|
89 |
|
90 | ```javascript
|
91 | // Generic "done" callback.
|
92 | function allDone(notAborted, arr) {
|
93 | console.log("done", notAborted, arr);
|
94 | }
|
95 |
|
96 | // Synchronous.
|
97 | forEach(["a", "b", "c"], function(item, index, arr) {
|
98 | console.log("each", item, index, arr);
|
99 | }, allDone);
|
100 | // logs:
|
101 | // each a 0 ["a", "b", "c"]
|
102 | // each b 1 ["a", "b", "c"]
|
103 | // each c 2 ["a", "b", "c"]
|
104 | // done true ["a", "b", "c"]
|
105 |
|
106 | // Synchronous with early abort.
|
107 | forEach(["a", "b", "c"], function(item, index, arr) {
|
108 | console.log("each", item, index, arr);
|
109 | if (item === "b") { return false; }
|
110 | }, allDone);
|
111 | // logs:
|
112 | // each a 0 ["a", "b", "c"]
|
113 | // each b 1 ["a", "b", "c"]
|
114 | // done false ["a", "b", "c"]
|
115 |
|
116 | // Asynchronous.
|
117 | forEach(["a", "b", "c"], function(item, index, arr) {
|
118 | console.log("each", item, index, arr);
|
119 | var done = this.async();
|
120 | setTimeout(function() {
|
121 | done();
|
122 | }, 500);
|
123 | }, allDone);
|
124 | // logs:
|
125 | // each a 0 ["a", "b", "c"]
|
126 | // each b 1 ["a", "b", "c"]
|
127 | // each c 2 ["a", "b", "c"]
|
128 | // done true ["a", "b", "c"]
|
129 |
|
130 | // Asynchronous with early abort.
|
131 | forEach(["a", "b", "c"], function(item, index, arr) {
|
132 | console.log("each", item, index, arr);
|
133 | var done = this.async();
|
134 | setTimeout(function() {
|
135 | done(item !== "b");
|
136 | }, 500);
|
137 | }, allDone);
|
138 | // logs:
|
139 | // each a 0 ["a", "b", "c"]
|
140 | // each b 1 ["a", "b", "c"]
|
141 | // done false ["a", "b", "c"]
|
142 |
|
143 | // Not actually asynchronous.
|
144 | forEach(["a", "b", "c"], function(item, index, arr) {
|
145 | console.log("each", item, index, arr);
|
146 | var done = this.async()
|
147 | done();
|
148 | }, allDone);
|
149 | // logs:
|
150 | // each a 0 ["a", "b", "c"]
|
151 | // each b 1 ["a", "b", "c"]
|
152 | // each c 2 ["a", "b", "c"]
|
153 | // done true ["a", "b", "c"]
|
154 |
|
155 | // Not actually asynchronous with early abort.
|
156 | forEach(["a", "b", "c"], function(item, index, arr) {
|
157 | console.log("each", item, index, arr);
|
158 | var done = this.async();
|
159 | done(item !== "b");
|
160 | }, allDone);
|
161 | // logs:
|
162 | // each a 0 ["a", "b", "c"]
|
163 | // each b 1 ["a", "b", "c"]
|
164 | // done false ["a", "b", "c"]
|
165 | ```
|
166 |
|
167 | ## Contributing
|
168 | 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).
|
169 |
|
170 | _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!_
|
171 |
|
172 | ## Release History
|
173 |
|
174 | 04/29/2013
|
175 | v0.1.3
|
176 | Removed hard Node.js version dependency.
|
177 |
|
178 | 11/17/2011
|
179 | v0.1.2
|
180 | Adding sparse array support.
|
181 | Invalid length properties are now sanitized.
|
182 | This closes issue #1 (like a boss).
|
183 |
|
184 | 11/11/2011
|
185 | v0.1.1
|
186 | Refactored code to be much simpler. Yay for unit tests!
|
187 |
|
188 | 11/11/2011
|
189 | v0.1.0
|
190 | Initial Release.
|
191 |
|
192 | ## License
|
193 | Copyright (c) 2012 "Cowboy" Ben Alman
|
194 | Licensed under the MIT license.
|
195 | <http://benalman.com/about/license/>
|