README.md (10352B)
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 # inmapAsync 22 23 > Invoke a function for each element in a collection and update the collection in-place. 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 inmapAsync = require( '@stdlib/utils/async/inmap' ); 41 ``` 42 43 #### inmapAsync( collection, \[options,] fcn, done ) 44 45 Invokes a function for each element in a `collection` and updates the `collection` in-place. 46 47 <!-- eslint-disable no-use-before-define --> 48 49 ```javascript 50 function fcn( value, index, next ) { 51 setTimeout( onTimeout, value ); 52 function onTimeout() { 53 console.log( value ); 54 next( null, value*index ); 55 } 56 } 57 58 function done( error, collection ) { 59 if ( error ) { 60 throw error; 61 } 62 console.log( collection === arr ); 63 console.log( collection ); 64 } 65 66 var arr = [ 3000, 2500, 1000 ]; 67 68 inmapAsync( arr, fcn, done ); 69 /* 70 1000 71 2500 72 3000 73 true 74 [ 0, 2500, 2000 ] 75 */ 76 ``` 77 78 The `next` callback accepts two arguments: `error` and `result`. The second argument to the `next` callback is used to update the `collection` element for the corresponding collection `index`, thus mutating the input `collection`. 79 80 ```javascript 81 function fcn( value, index, next ) { 82 setTimeout( onTimeout, value ); 83 function onTimeout() { 84 next( null, 'beep: '+index ); 85 } 86 } 87 88 function done( error, collection ) { 89 if ( error ) { 90 throw error; 91 } 92 console.log( collection ); 93 // => [ 'beep: 0', 'beep: 1', 'beep: 2' ] 94 } 95 96 var arr = [ 3000, 2500, 1000 ]; 97 98 inmapAsync( arr, fcn, done ); 99 ``` 100 101 If the `next` callback is called with an `error` argument, the input `collection` may be **partially** mutated. 102 103 ```javascript 104 function fcn( value, index, next ) { 105 setTimeout( onTimeout, value ); 106 function onTimeout() { 107 if ( index === 1 ) { 108 return next( new Error( 'boop' ) ); 109 } 110 next( null, 'beep: '+index ); 111 } 112 } 113 114 function done( error, collection ) { 115 if ( error ) { 116 // Ignore error... 117 } 118 console.log( collection ); 119 // => [ 'beep: 0', 2000, 3000 ] 120 } 121 122 var arr = [ 1000, 2000, 3000 ]; 123 124 inmapAsync( arr, fcn, done ); 125 ``` 126 127 The function accepts the following `options`: 128 129 - `limit`: the maximum number of pending invocations at any one time. Default: `infinity`. 130 - `series`: `boolean` indicating whether to sequentially invoke `fcn` for each `collection` element. If `true`, the function sets `options.limit=1`. Default: `false`. 131 - `thisArg`: the execution context for `fcn`. 132 133 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`. 134 135 <!-- eslint-disable no-use-before-define --> 136 137 ```javascript 138 function fcn( value, index, next ) { 139 setTimeout( onTimeout, value ); 140 function onTimeout() { 141 console.log( value ); 142 next( null, value*index ); 143 } 144 } 145 146 function done( error, collection ) { 147 if ( error ) { 148 throw error; 149 } 150 console.log( collection === arr ); 151 console.log( collection ); 152 } 153 154 var arr = [ 3000, 2500, 1000 ]; 155 156 var opts = { 157 'series': true 158 }; 159 160 inmapAsync( arr, opts, fcn, done ); 161 /* => 162 3000 163 2500 164 1000 165 true 166 [ 0, 2500, 2000 ] 167 */ 168 ``` 169 170 To limit the maximum number of pending function invocations, set the `limit` option. 171 172 <!-- eslint-disable no-use-before-define --> 173 174 ```javascript 175 function fcn( value, index, next ) { 176 setTimeout( onTimeout, value ); 177 function onTimeout() { 178 console.log( value ); 179 next( null, value*index ); 180 } 181 } 182 183 function done( error, collection ) { 184 if ( error ) { 185 throw error; 186 } 187 console.log( collection === arr ); 188 console.log( collection ); 189 } 190 191 var arr = [ 3000, 2500, 1000 ]; 192 193 var opts = { 194 'limit': 2 195 }; 196 197 inmapAsync( arr, opts, fcn, done ); 198 /* => 199 2500 200 3000 201 1000 202 true, 203 [ 0, 2500, 2000 ] 204 */ 205 ``` 206 207 To set the execution context of `fcn`, set the `thisArg` option. 208 209 <!-- eslint-disable no-use-before-define --> 210 211 ```javascript 212 function fcn( value, index, next ) { 213 this.count += 1; 214 setTimeout( onTimeout, value ); 215 function onTimeout() { 216 next( null, value*index ); 217 } 218 } 219 220 var arr = [ 3000, 2500, 1000 ]; 221 222 var context = { 223 'count': 0 224 }; 225 226 var opts = { 227 'thisArg': context 228 }; 229 230 inmapAsync( arr, opts, fcn, done ); 231 232 function done( error, collection ) { 233 if ( error ) { 234 throw error; 235 } 236 console.log( collection === arr ); 237 // => true 238 239 console.log( collection ); 240 // => [ 0, 2500, 2000 ] 241 242 console.log( context.count ); 243 // => 3 244 } 245 ``` 246 247 When invoked, `fcn` is provided a maximum of four arguments: 248 249 - `value`: collection value. 250 - `index`: collection index. 251 - `collection`: the input `collection`. 252 - `next`: a callback which should be called once `fcn` has finished processing a collection `value`. 253 254 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. 255 256 <!-- eslint-disable no-use-before-define --> 257 258 ```javascript 259 function fcn( value, i, collection, next ) { 260 console.log( 'collection: %s. %d: %d', collection.join( ',' ), i, value ); 261 setTimeout( onTimeout, value ); 262 function onTimeout() { 263 console.log( value ); 264 next( null, value*i ); 265 } 266 } 267 268 function done( error, collection ) { 269 if ( error ) { 270 throw error; 271 } 272 console.log( collection === arr ); 273 // => true 274 275 console.log( collection ); 276 // => [ 0, 2500, 2000 ] 277 } 278 279 var arr = [ 3000, 2500, 1000 ]; 280 281 inmapAsync( arr, fcn, done ); 282 /* => 283 collection: 3000,2500,1000. 0: 3000 284 collection: 3000,2500,1000. 1: 2500 285 collection: 3000,2500,1000. 2: 1000 286 1000 287 2500 288 3000 289 */ 290 ``` 291 292 #### inmapAsync.factory( \[options,] fcn ) 293 294 Returns a `function` which invokes a function once for each element in a `collection`. 295 296 ```javascript 297 function fcn( value, index, next ) { 298 setTimeout( onTimeout, value ); 299 function onTimeout() { 300 console.log( value ); 301 next( null, value*index ); 302 } 303 } 304 305 function done( error, collection ) { 306 if ( error ) { 307 throw error; 308 } 309 console.log( collection ); 310 } 311 312 var f = inmapAsync.factory( fcn ); 313 314 var arr1 = [ 3000, 2500, 1000 ]; 315 316 f( arr1, done ); 317 /* => 318 1000 319 2500 320 3000 321 [ 0, 2500, 2000 ] 322 */ 323 324 var arr2 = [ 300, 250, 100 ]; 325 326 f( arr2, done ); 327 /* => 328 100 329 250 330 300 331 [ 0, 250, 200 ] 332 */ 333 ``` 334 335 The function accepts the same `options` as `inmapAsync()`. 336 337 </section> 338 339 <!-- /.usage --> 340 341 <!-- Package usage notes. Make sure to keep an empty line after the `section` element and another before the `/section` close. --> 342 343 <section class="notes"> 344 345 ## Notes 346 347 - 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`). 348 - 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. 349 - The function invokes the `done` callback with the input `collection` provided as the second argument. 350 - The function modifies `collection` elements in-place. 351 - The function does **not** support dynamic `collection` resizing. 352 - The function does **not** skip `undefined` elements. 353 - **Neither** `inmapAsync` 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`). 354 355 </section> 356 357 <!-- /.notes --> 358 359 <!-- Package usage examples. --> 360 361 <section class="examples"> 362 363 ## Examples 364 365 <!-- eslint no-undef: "error" --> 366 367 ```javascript 368 var resolve = require( 'path' ).resolve; 369 var readFile = require( '@stdlib/fs/read-file' ); 370 var inmapAsync = require( '@stdlib/utils/async/inmap' ); 371 372 var files = [ 373 resolve( __dirname, 'package.json' ), 374 resolve( __dirname, 'README.md' ) 375 ]; 376 377 function done( error, results ) { 378 if ( error ) { 379 throw error; 380 } 381 console.log( results ); 382 } 383 384 function read( file, next ) { 385 var opts = { 386 'encoding': 'utf8' 387 }; 388 readFile( file, opts, onFile ); 389 390 function onFile( error, data ) { 391 if ( error ) { 392 error = new Error( 'unable to read file: '+file ); 393 return next( error ); 394 } 395 next( null, data ); 396 } 397 } 398 399 inmapAsync( files, read, done ); 400 ``` 401 402 </section> 403 404 <!-- /.examples --> 405 406 <!-- 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. --> 407 408 <section class="references"> 409 410 </section> 411 412 <!-- /.references --> 413 414 <!-- Section for all links. Make sure to keep an empty line after the `section` element and another before the `/section` close. --> 415 416 <section class="links"> 417 418 [mdn-array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array 419 420 [mdn-typed-array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray 421 422 [mdn-object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object 423 424 </section> 425 426 <!-- /.links -->