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