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