README.md (8036B)
1 <!-- 2 3 @license Apache-2.0 4 5 Copyright (c) 2018 The Stdlib Authors. 6 7 Licensed under the Apache License, Version 2.0 (the "License"); 8 you may not use this file except in compliance with the License. 9 You may obtain a copy of the License at 10 11 http://www.apache.org/licenses/LICENSE-2.0 12 13 Unless required by applicable law or agreed to in writing, software 14 distributed under the License is distributed on an "AS IS" BASIS, 15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 See the License for the specific language governing permissions and 17 limitations under the License. 18 19 --> 20 21 # forEachAsync 22 23 > Invoke a function once for each element in a collection. 24 25 <!-- Section to include introductory text. Make sure to keep an empty line after the intro `section` element and another before the `/section` close. --> 26 27 <section class="intro"> 28 29 </section> 30 31 <!-- /.intro --> 32 33 <!-- Package usage documentation. --> 34 35 <section class="usage"> 36 37 ## Usage 38 39 ```javascript 40 var forEachAsync = require( '@stdlib/utils/async/for-each' ); 41 ``` 42 43 #### forEachAsync( collection, \[options,] fcn, done ) 44 45 Invokes a function once for each element in a `collection`. 46 47 ```javascript 48 function onDuration( value, next ) { 49 setTimeout( onTimeout, value ); 50 function onTimeout() { 51 console.log( value ); 52 next(); 53 } 54 } 55 56 function done( error ) { 57 if ( error ) { 58 throw error; 59 } 60 } 61 62 var arr = [ 3000, 2500, 1000 ]; 63 64 forEachAsync( arr, onDuration, done ); 65 /* => 66 1000 67 2500 68 3000 69 */ 70 ``` 71 72 The function accepts the following `options`: 73 74 - `limit`: the maximum number of pending invocations at any one time. Default: `infinity`. 75 - `series`: `boolean` indicating whether to sequentially invoke `fcn` for each `collection` element. If `true`, the function sets `options.limit=1`. Default: `false`. 76 - `thisArg`: the execution context for `fcn`. 77 78 By default, all elements are processed concurrently, which means that the function does **not** guarantee completion order. To process each `collection` element sequentially, set the `series` option to `true`. 79 80 ```javascript 81 function onDuration( value, next ) { 82 setTimeout( onTimeout, value ); 83 function onTimeout() { 84 console.log( value ); 85 next(); 86 } 87 } 88 89 function done( error ) { 90 if ( error ) { 91 throw error; 92 } 93 } 94 95 var arr = [ 3000, 2500, 1000 ]; 96 97 var opts = { 98 'series': true 99 }; 100 101 forEachAsync( arr, opts, onDuration, done ); 102 /* => 103 3000 104 2500 105 1000 106 */ 107 ``` 108 109 To limit the maximum number of pending function invocations, set the `limit` option. 110 111 ```javascript 112 function onDuration( value, next ) { 113 setTimeout( onTimeout, value ); 114 function onTimeout() { 115 console.log( value ); 116 next(); 117 } 118 } 119 120 function done( error ) { 121 if ( error ) { 122 throw error; 123 } 124 } 125 126 var arr = [ 3000, 2500, 1000 ]; 127 128 var opts = { 129 'limit': 2 130 }; 131 132 forEachAsync( arr, opts, onDuration, done ); 133 /* => 134 2500 135 3000 136 1000 137 */ 138 ``` 139 140 To set the execution context of `fcn`, set the `thisArg` option. 141 142 ```javascript 143 function onDuration( value, next ) { 144 this.count += 1; 145 setTimeout( onTimeout, value ); 146 function onTimeout() { 147 next(); 148 } 149 } 150 151 var arr = [ 3000, 2500, 1000 ]; 152 153 var context = { 154 'count': 0 155 }; 156 157 var opts = { 158 'thisArg': context 159 }; 160 161 forEachAsync( arr, opts, onDuration, done ); 162 163 function done( error ) { 164 if ( error ) { 165 throw error; 166 } 167 console.log( context.count ); 168 // => 3 169 } 170 ``` 171 172 When invoked, `fcn` is provided a maximum of four arguments: 173 174 - `value`: collection value. 175 - `index`: collection index. 176 - `collection`: the input `collection`. 177 - `next`: a callback which should be called once `fcn` has finished processing a collection `value`. 178 179 The actual number of provided arguments depends on function `length`. If `fcn` accepts two arguments, `fcn` is provided `value` and `next`. If `fcn` accepts three arguments, `fcn` is provided `value`, `index`, and `next`. For every other `fcn` signature, `fcn` is provided all four arguments. 180 181 ```javascript 182 function onDuration( value, i, collection, next ) { 183 console.log( 'collection: %s. %d: %d', collection.join( ',' ), i, value ); 184 setTimeout( onTimeout, value ); 185 function onTimeout() { 186 console.log( value ); 187 next(); 188 } 189 } 190 191 function done( error ) { 192 if ( error ) { 193 throw error; 194 } 195 } 196 197 var arr = [ 3000, 2500, 1000 ]; 198 199 forEachAsync( arr, onDuration, done ); 200 /* => 201 collection: 3000,2500,1000. 0: 3000 202 collection: 3000,2500,1000. 1: 2500 203 collection: 3000,2500,1000. 2: 1000 204 1000 205 2500 206 3000 207 */ 208 ``` 209 210 #### forEachAsync.factory( \[options,] fcn ) 211 212 Returns a `function` which invokes a function once for each element in a `collection`. 213 214 ```javascript 215 function onDuration( value, next ) { 216 setTimeout( onTimeout, value ); 217 function onTimeout() { 218 console.log( value ); 219 next(); 220 } 221 } 222 223 function done( error ) { 224 if ( error ) { 225 throw error; 226 } 227 } 228 229 var f = forEachAsync.factory( onDuration ); 230 231 var arr1 = [ 3000, 2500, 1000 ]; 232 233 f( arr1, done ); 234 /* => 235 1000 236 2500 237 3000 238 */ 239 240 var arr2 = [ 300, 250, 100 ]; 241 242 f( arr2, done ); 243 /* => 244 100 245 250 246 300 247 */ 248 ``` 249 250 The function accepts the same `options` as `forEachAsync()`. 251 252 </section> 253 254 <!-- /.usage --> 255 256 <!-- Package usage notes. Make sure to keep an empty line after the `section` element and another before the `/section` close. --> 257 258 <section class="notes"> 259 260 ## Notes 261 262 - A `collection` may be either an [`Array`][mdn-array], [`Typed Array`][mdn-typed-array], or an array-like [`Object`][mdn-object] (excluding `strings` and `functions`). 263 - If a provided function calls the `next` callback with a truthy `error` argument, the function suspends execution and immediately calls the `done` callback for subsequent `error` handling. 264 - The function does **not** support dynamic `collection` resizing. 265 - The function does **not** skip `undefined` elements. 266 - **Neither** `forEachAsync` nor the function returned by the `factory` method **guarantee** asynchronous execution. To guarantee asynchrony, wrap the `done` callback in a function which either executes at the end of the current stack (e.g., `nextTick`) or during a subsequent turn of the event loop (e.g., `setImmediate`, `setTimeout`). 267 268 </section> 269 270 <!-- /.notes --> 271 272 <!-- Package usage examples. --> 273 274 <section class="examples"> 275 276 ## Examples 277 278 <!-- eslint no-undef: "error" --> 279 280 ```javascript 281 var resolve = require( 'path' ).resolve; 282 var readFile = require( '@stdlib/fs/read-file' ); 283 var forEachAsync = require( '@stdlib/utils/async/for-each' ); 284 285 var files = [ 286 resolve( __dirname, 'package.json' ), 287 resolve( __dirname, 'README.md' ) 288 ]; 289 290 function done( error ) { 291 if ( error ) { 292 throw error; 293 } 294 console.log( 'Successfully read all files.' ); 295 } 296 297 function read( file, next ) { 298 var opts = { 299 'encoding': 'utf8' 300 }; 301 readFile( file, opts, onFile ); 302 303 function onFile( error ) { 304 if ( error ) { 305 error = new Error( 'unable to read file: '+file ); 306 return next( error ); 307 } 308 console.log( 'Successfully read file: %s', file ); 309 next(); 310 } 311 } 312 313 forEachAsync( files, read, done ); 314 ``` 315 316 </section> 317 318 <!-- /.examples --> 319 320 <!-- Section to include cited references. If references are included, add a horizontal rule *before* the section. Make sure to keep an empty line after the `section` element and another before the `/section` close. --> 321 322 <section class="references"> 323 324 </section> 325 326 <!-- /.references --> 327 328 <!-- Section for all links. Make sure to keep an empty line after the `section` element and another before the `/section` close. --> 329 330 <section class="links"> 331 332 [mdn-array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array 333 334 [mdn-typed-array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray 335 336 [mdn-object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object 337 338 </section> 339 340 <!-- /.links -->