doUntilAsync

Invoke a function until a test condition is true.

Usage

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

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

Invokes a function until a predicate function returns true. Note that the predicate function is evaluated after executing fcn; thus, fcn always executes at least once.

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;
    }
}

doUntilAsync( 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 falsy, 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.

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
}

doUntilAsync( fcn, predicate, done );

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

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
}

doUntilAsync( fcn, predicate, done );

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

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
};

doUntilAsync( 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

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

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 );
}

doUntilAsync( fcn, predicate, done );
Did you find this page helpful?