untilAsync

Invoke a function until a test condition is true.

Usage

var untilAsync = require( '@stdlib/utils/until-async' );

untilAsync( predicate, fcn, done[, thisArg ] )

Invokes a function until a predicate function returns true.

function predicate( i, clbk ) {
    clbk( null, i >= 5 );
}

function fcn( i, next ) {
    setTimeout( onTimeout, 0 );
    function onTimeout() {
        console.log( 'beep: %d', i );
        next();
    }
}

function done( error ) {
    if ( error ) {
        throw error;
    }
}

untilAsync( predicate, fcn, done );
/* =>
    beep: 0
    beep: 1
    beep: 2
    beep: 3
    beep: 4
*/

The predicate function is provided two arguments:

  • i: iteration number (starting from zero)
  • 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 falsy, the function invokes fcn; otherwise, the function invokes the done callback.

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 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.

function predicate( i, clbk ) {
    clbk( null, i >= 5 );
}

function fcn( i, next ) {
    setTimeout( onTimeout, 0 );
    function onTimeout() {
        next( new Error( 'beep' ) );
    }
}

function done( error ) {
    console.error( error.message );
    // => beep
}

untilAsync( predicate, fcn, done );

The done callback is invoked with an error argument and any arguments passed to the final next callback.

function predicate( i, clbk ) {
    clbk( null, i >= 5 );
}

function fcn( i, next ) {
    setTimeout( onTimeout, 0 );
    function onTimeout() {
        next( null, i );
    }
}

function done( error, result ) {
    if ( error ) {
        throw error;
    }
    console.log( result );
    // => 4
}

untilAsync( predicate, fcn, done );

To set the function execution context for the invoked function, provide a thisArg.

function predicate( i, clbk ) {
    clbk( null, i >= 5 );
}

function fcn( i, next ) {
    this.count += 1;
    setTimeout( onTimeout, 0 );
    function onTimeout() {
        next();
    }
}

function done( error ) {
    if ( error ) {
        throw error;
    }
}

var context = {
    'count': 0
};

untilAsync( predicate, fcn, done, context );

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

var repeatString = require( '@stdlib/string/repeat' );
var untilAsync = require( '@stdlib/utils/until-async' );

function predicate( i, clbk ) {
    setTimeout( onTimeout, 0 );
    function onTimeout() {
        clbk( null, i >= 5 );
    }
}

function fcn( i, next ) {
    setTimeout( onTimeout, 0 );
    function onTimeout() {
        next( null, repeatString( 'beep', i+1 ) );
    }
}

function done( error, result ) {
    if ( error ) {
        throw error;
    }
    console.log( result );
}

untilAsync( predicate, fcn, done );