lib/Function.js
/**
 * Wraps a task into another one that will attempt to get a successful response from the wrapt task with the given conditions.
 *
 * @param {number|function(i)} [times]
 *  Wrapt task will be executed no more than 'times' times before returning an error.
 *  If 'times' is a function then it will be called with the count of unsuccessful attempts on every retry
 *  to get the remaining attempt count.
 * @param {number|function(i)} [backoff]
 *  Wait 'backoff' milliseconds before the next attempt.
 *  If 'backoff' is a function then it will be called with the count of unsuccessful attempts on every retry
 *  to get the delay before next attempt.
 * @returns {task(done)}
 */
Wraps a task into another one that will attempt to get a successful response from the wrapt task with the given conditions.
@param {number|function(i)} [times]
Wrapt task will be executed no more than 'times' times before returning an error.
If 'times' is a function then it will be called with the count of unsuccessful attempts on every retry
to get the remaining attempt count.
@param {number|function(i)} [backoff]
Wait 'backoff' milliseconds before the next attempt.
If 'backoff' is a function then it will be called with the count of unsuccessful attempts on every retry
to get the delay before next attempt.
Wraps a task into another one that will attempt to get a successful response from the wrapt task with the given conditions . @param { number|function ( i ) } [ times ] Wrapt task will be executed no more than ' times ' times before returning an error . If ' times ' is a function then it will be called with the count of unsuccessful attempts on every retry to get the remaining attempt count . @param { number|function ( i ) } [ backoff ] Wait ' backoff ' milliseconds before the next attempt . If ' backoff ' is a function then it will be called with the count of unsuccessful attempts on every retry to get the delay before next attempt .
function retry(times, backoff) {
    assert(!arguments.length     || !isNaN(+times)   || times   instanceof Function, 'If provided, first argument of <task>.retry([times][, backoff]) must be a number or function.')
    assert(arguments.length <= 1 || !isNaN(+backoff) || backoff instanceof Function, 'If provided, second argument of <task>.retry([times][, backoff]) must be a number or function.')
    if(!arguments.length)
        times = 1
    if(!(times instanceof Function))
        times = (function (i) { return this - i }).bind(+times)
    if(!(backoff instanceof Function))
        backoff = (function () { return this }).bind(+backoff)
    var fn = this,
        i  = 0,
        aborted
    var again = function(done, recall) {
        if(aborted) return
        if(recall) i = 0
        fn(function (err) {
            if (err) {
                if (Math.max(Math.round(+times(i) || 0), 0))
                    setTimeout(again.bind(0, done), Math.max(Math.round(+backoff(i++) || 0), 0))
                else
                    done(err)
            }
            else
                done.apply(fn, arguments)
        }, true)
    }
    return decorateTask(again, true, function (reason) {
        if(fn.abort)
            fn.abort(reason)
        aborted = true
    })
}
function retry ( times , backoff ) { assert ( ! arguments . length || ! isNaN ( + times ) || times instanceof Function , 'If provided, first argument of <task>.retry([times][, backoff]) must be a number or function.' ) assert ( arguments . length <= 1 || ! isNaN ( + backoff ) || backoff instanceof Function , 'If provided, second argument of <task>.retry([times][, backoff]) must be a number or function.' ) if ( ! arguments . length ) times = 1 if ( ! ( times instanceof Function ) ) times = ( function ( i ) { return this - i } ) . bind ( + times ) if ( ! ( backoff instanceof Function ) ) backoff = ( function ( ) { return this } ) . bind ( + backoff ) var fn = this , i = 0 , aborted var again = function ( done , recall ) { if ( aborted ) return if ( recall ) i = 0 fn ( function ( err ) { if ( err ) { if ( Math . max ( Math . round ( + times ( i ) || 0 ) , 0 ) ) setTimeout ( again . bind ( 0 , done ) , Math . max ( Math . round ( + backoff ( i ++ ) || 0 ) , 0 ) ) else done ( err ) } else done . apply ( fn , arguments ) } , true ) } return decorateTask ( again , true , function ( reason ) { if ( fn . abort ) fn . abort ( reason ) aborted = true } ) }
Wraps a task into another one that will attempt to get a successful response from the wrapt task with the given conditions.
Wraps a task into another one that will attempt to get a successful response from the wrapt task with the given conditions .