untilAsync

    Invoke a function until a test condition is true.

    Usage

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

    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();
        }
    }
    
    var context = {
        'count': 0
    };
    
    untilAsync( predicate, fcn, 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 untilAsync = require( '@stdlib/utils/async/until' );
    
    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 );