# doWhileAsync
> Invoke a function while a test condition is true.
## Usage
```javascript
var doWhileAsync = require( '@stdlib/utils/async/do-while' );
```
#### doWhileAsync( fcn, predicate, done\[, thisArg ] )
Invokes a `function` until a `predicate` function returns `false`. Note that the `predicate` function is evaluated **after** executing `fcn`; thus, `fcn` **always** executes at least once.
```javascript
function fcn( i, next ) {
setTimeout( onTimeout, 0 );
function onTimeout() {
console.log( 'beep: %d', i );
next();
}
}
function predicate( i, clbk ) {
clbk( null, i < 5 );
}
function done( error ) {
if ( error ) {
throw error;
}
}
doWhileAsync( fcn, predicate, done );
/* =>
beep: 0
beep: 1
beep: 2
beep: 3
beep: 4
*/
```
The function to invoke is provided two arguments:
- `i`: iteration number (starting from zero)
- `next`: a callback which must be invoked before proceeding to the next iteration
The `predicate` function is provided two arguments:
- `i`: iteration number (starting from one)
- `clbk`: a callback indicating whether to invoke `fcn`
The `clbk` function accepts two arguments:
- `error`: error object
- `bool`: test result
If the test result is truthy, the function continues invoking `fcn`; otherwise, the function invokes the `done` callback.
The first argument of both `clbk` and `next` is an `error` argument. If either function is called with a truthy `error` argument, the function suspends execution and immediately calls the `done` callback for subsequent `error` handling.
```javascript
function fcn( i, next ) {
setTimeout( onTimeout, 0 );
function onTimeout() {
next( new Error( 'beep' ) );
}
}
function predicate( i, clbk ) {
clbk( null, i < 5 );
}
function done( error ) {
console.error( error.message );
// => beep
}
doWhileAsync( fcn, predicate, done );
```
The `done` callback is invoked with an `error` argument and any arguments passed to the final `next` callback.
```javascript
function fcn( i, next ) {
setTimeout( onTimeout, 0 );
function onTimeout() {
next( null, i );
}
}
function predicate( i, clbk ) {
clbk( null, i < 5 );
}
function done( error, result ) {
if ( error ) {
throw error;
}
console.log( result );
// => 4
}
doWhileAsync( fcn, predicate, done );
```
To set the function execution context for the invoked function, provide a `thisArg`.
```javascript
function fcn( i, next ) {
this.count += 1;
setTimeout( onTimeout, 0 );
function onTimeout() {
next();
}
}
function predicate( i, clbk ) {
clbk( null, i < 5 );
}
var context = {
'count': 0
};
doWhileAsync( fcn, predicate, done, context );
function done( error ) {
if ( error ) {
throw error;
}
console.log( context.count );
// => 5
}
```
## Notes
- Execution is **not** guaranteed to be asynchronous. 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 repeatString = require( '@stdlib/string/repeat' );
var doWhileAsync = require( '@stdlib/utils/async/do-while' );
function fcn( i, next ) {
setTimeout( onTimeout, 0 );
function onTimeout() {
next( null, repeatString( 'beep', i+1 ) );
}
}
function predicate( i, clbk ) {
setTimeout( onTimeout, 0 );
function onTimeout() {
clbk( null, i < 5 );
}
}
function done( error, result ) {
if ( error ) {
throw error;
}
console.log( result );
}
doWhileAsync( fcn, predicate, done );
```