README.md (10521B)
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 # inmapRightAsync 22 23 > Invoke a function for each element in a collection and update the collection in-place, iterating from right to left. 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 inmapRightAsync = require( '@stdlib/utils/async/inmap-right' ); 41 ``` 42 43 #### inmapRightAsync( collection, \[options,] fcn, done ) 44 45 Invokes a function for each element in a `collection` and updates the `collection` in-place, iterating from right to left. 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 = [ 1000, 2500, 3000 ]; 67 68 inmapRightAsync( arr, fcn, done ); 69 /* 70 1000 71 2500 72 3000 73 true 74 [ 0, 2500, 6000 ] 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 = [ 1000, 2500, 3000 ]; 97 98 inmapRightAsync( 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 // => [ 1000, 2000, 'beep: 2' ] 120 } 121 122 var arr = [ 1000, 2000, 3000 ]; 123 124 inmapRightAsync( 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 = [ 1000, 2500, 3000 ]; 155 156 var opts = { 157 'series': true 158 }; 159 160 inmapRightAsync( arr, opts, fcn, done ); 161 /* => 162 3000 163 2500 164 1000 165 true 166 [ 0, 2500, 6000 ] 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 = [ 1000, 2500, 3000 ]; 192 193 var opts = { 194 'limit': 2 195 }; 196 197 inmapRightAsync( arr, opts, fcn, done ); 198 /* => 199 2500 200 3000 201 1000 202 true, 203 [ 0, 2500, 6000 ] 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 = [ 1000, 2500, 3000 ]; 221 222 var context = { 223 'count': 0 224 }; 225 226 var opts = { 227 'thisArg': context 228 }; 229 230 inmapRightAsync( 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, 6000 ] 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 console.log( collection ); 274 } 275 276 var arr = [ 1000, 2500, 3000 ]; 277 278 inmapRightAsync( arr, fcn, done ); 279 /* => 280 collection: 3000,2500,1000. 2: 3000 281 collection: 3000,2500,1000. 1: 2500 282 collection: 3000,2500,1000. 0: 1000 283 1000 284 2500 285 3000 286 true 287 [ 0, 2500, 6000 ] 288 */ 289 ``` 290 291 #### inmapRightAsync.factory( \[options,] fcn ) 292 293 Returns a `function` which invokes a function once for each element in a `collection`, iterating from right to left. 294 295 ```javascript 296 function fcn( value, index, next ) { 297 setTimeout( onTimeout, value ); 298 function onTimeout() { 299 console.log( value ); 300 next( null, value*index ); 301 } 302 } 303 304 function done( error, collection ) { 305 if ( error ) { 306 throw error; 307 } 308 console.log( collection ); 309 } 310 311 var f = inmapRightAsync.factory( fcn ); 312 313 var arr1 = [ 1000, 2500, 3000 ]; 314 315 f( arr1, done ); 316 /* => 317 1000 318 2500 319 3000 320 [ 0, 2500, 6000 ] 321 */ 322 323 var arr2 = [ 100, 250, 300 ]; 324 325 f( arr2, done ); 326 /* => 327 100 328 250 329 300 330 [ 0, 250, 600 ] 331 */ 332 ``` 333 334 The function accepts the same `options` as `inmapRightAsync()`. 335 336 </section> 337 338 <!-- /.usage --> 339 340 <!-- Package usage notes. Make sure to keep an empty line after the `section` element and another before the `/section` close. --> 341 342 <section class="notes"> 343 344 ## Notes 345 346 - 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`). 347 - 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. 348 - The function invokes the `done` callback with the input `collection` provided as the second argument. 349 - The function modifies `collection` elements in-place. 350 - The function does **not** support dynamic `collection` resizing. 351 - The function does **not** skip `undefined` elements. 352 - **Neither** `inmapRightAsync` 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`). 353 354 </section> 355 356 <!-- /.notes --> 357 358 <!-- Package usage examples. --> 359 360 <section class="examples"> 361 362 ## Examples 363 364 <!-- eslint no-undef: "error" --> 365 366 ```javascript 367 var resolve = require( 'path' ).resolve; 368 var readFile = require( '@stdlib/fs/read-file' ); 369 var inmapRightAsync = require( '@stdlib/utils/async/inmap-right' ); 370 371 var files = [ 372 resolve( __dirname, 'package.json' ), 373 resolve( __dirname, 'README.md' ) 374 ]; 375 376 function done( error, results ) { 377 if ( error ) { 378 throw error; 379 } 380 console.log( results ); 381 } 382 383 function read( file, next ) { 384 var opts = { 385 'encoding': 'utf8' 386 }; 387 readFile( file, opts, onFile ); 388 389 function onFile( error, data ) { 390 if ( error ) { 391 error = new Error( 'unable to read file: '+file ); 392 return next( error ); 393 } 394 next( null, data ); 395 } 396 } 397 398 inmapRightAsync( files, read, done ); 399 ``` 400 401 </section> 402 403 <!-- /.examples --> 404 405 <!-- 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. --> 406 407 <section class="references"> 408 409 </section> 410 411 <!-- /.references --> 412 413 <!-- Section for all links. Make sure to keep an empty line after the `section` element and another before the `/section` close. --> 414 415 <section class="links"> 416 417 [mdn-array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array 418 419 [mdn-typed-array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray 420 421 [mdn-object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object 422 423 </section> 424 425 <!-- /.links -->