# mapFunAsync
> Invoke a function `n` times and return an array of accumulated function return values.
## Usage
```javascript
var mapFunAsync = require( '@stdlib/utils/async/map-function' );
```
#### mapFunAsync( fcn, n, \[options,] done )
Invokes a function `n` times and returns an `array` of accumulated function return values.
```javascript
function fcn( i, next ) {
var t = 300 - (i*50);
setTimeout( onTimeout, t );
function onTimeout() {
console.log( i );
next( null, i );
}
}
function done( error, arr ) {
if ( error ) {
throw error;
}
console.log( arr );
}
mapFunAsync( fcn, 5, done );
/* =>
4
3
2
1
0
[ 0, 1, 2, 3, 4 ]
*/
```
For each iteration, the provided function is invoked with two arguments:
- `index`: invocation index (starting from zero)
- `next`: callback to be invoked upon function completion
The `next` callback accepts two arguments:
- `error`: error argument
- `result`: function result
The function accepts the following `options`:
- `limit`: the maximum number of pending invocations at any one time. Default: `infinity`.
- `series`: `boolean` indicating whether to sequentially invoke `fcn`. If `true`, the function sets `options.limit=1`. Default: `false`.
- `thisArg`: the execution context for `fcn`.
By default, all invocations are performed concurrently, which means that the function does **not** guarantee completion order. To invoke a function such that only one invocation is pending at any one time, set the `series` option to `true`.
```javascript
function fcn( i, next ) {
var t = 300 - (i*50);
setTimeout( onTimeout, t );
function onTimeout() {
console.log( i );
next( null, i );
}
}
function done( error, arr ) {
if ( error ) {
throw error;
}
console.log( arr );
}
var opts = {
'series': true
};
mapFunAsync( fcn, 5, opts, done );
/* =>
0
1
2
3
4
[ 0, 1, 2, 3, 4 ]
*/
```
To limit the maximum number of pending function invocations, set the `limit` option.
```javascript
var delays = [ 300, 250, 225, 150, 100 ];
function fcn( i, next ) {
setTimeout( onTimeout, delays[ i ] );
function onTimeout() {
console.log( i );
next( null, i );
}
}
function done( error, arr ) {
if ( error ) {
throw error;
}
console.log( arr );
}
var opts = {
'limit': 2
};
mapFunAsync( fcn, 5, opts, done );
/* =>
1
0
3
2
4
[ 0, 1, 2, 3, 4 ]
*/
```
To set the execution context of `fcn`, set the `thisArg` option.
```javascript
function fcn( i, next ) {
this.count += 1;
setTimeout( onTimeout, 0 );
function onTimeout() {
next( null, i );
}
}
function done( error, arr ) {
if ( error ) {
throw error;
}
console.log( arr );
// => [ 0, 1, 2, 3, 4 ]
}
var ctx = {
'count': 0
};
var opts = {
'thisArg': ctx
};
mapFunAsync( fcn, 5, opts, done );
```
#### mapFunAsync.factory( \[options,] fcn )
Returns a `function` which invokes a function `n` times and returns an `array` of accumulated function return values.
```javascript
function fcn( i, next ) {
var t = 300 - (i*50);
setTimeout( onTimeout, t );
function onTimeout() {
console.log( i );
next( null, i );
}
}
function done( error, arr ) {
if ( error ) {
throw error;
}
console.log( arr );
}
var opts = {
'series': true
};
var f = mapFunAsync.factory( opts, fcn );
f( 5, done );
/* =>
0
1
2
3
4
[ 0, 1, 2, 3, 4 ]
*/
f( 2, done );
/* =>
0
1
[ 0, 1 ]
*/
```
The function accepts the same `options` as `mapFunAsync()`.
## Notes
- 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.
- **Neither** `mapFunAsync` 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`).
## Examples
```javascript
var randu = require( '@stdlib/random/base/randu' );
var mapFunAsync = require( '@stdlib/utils/async/map-function' );
function rand( i, next ) {
var t = randu() * i;
setTimeout( onTimeout, t );
function onTimeout() {
next( null, t );
}
}
function done( error, out ) {
if ( error ) {
throw error;
}
console.log( out );
}
mapFunAsync( rand, 10, done );
```