index.js
function _raco (iter, args, callback, opts) {
  var self = this
  var trycatch = true
  var isYieldable = true
  var yielded = false
  var nothrow = !!opts.nothrow
  /**
   * internal callback stepper
   *
   * @param {object} err - callback error object
   * @param {...*} val - callback value(s)
   */
  function step (err, val) {
    if (iter) {
      // generator step
      yielded = false
      isYieldable = false
      var state
      if (trycatch) {
        try {
          if (nothrow) state = iter.next(slice.call(arguments))
          else state = err ? iter.throw(err) : iter.next(val)
        } catch (err) {
          iter = null // catch err, break iteration
          return step(err)
        }
      } else {
        if (nothrow) state = iter.next(slice.call(arguments))
        else state = err ? iter.throw(err) : iter.next(val)
      }
      if (state && state.done) iter = null
      yielded = true
      isYieldable = yieldable.call(self, state.value, step, opts)
      if (!isYieldable && opts.yieldable) {
        isYieldable = opts.yieldable.call(self, state.value, step)
      }
      // next if generator returned non-yieldable
      if (!isYieldable && !iter) next(null, state.value)
    } else if (callback) {
      callback.apply(self, arguments)
      callback = null
    }
  }
  /**
   * next, callback stepper with nextTick
   *
   * @param {object} err - callback error object
   * @param {...*} val - callback value(s)
   */
  function next () {
    var args = slice.call(arguments)
    if (!isYieldable) {
      // only handle callback if not yieldable
      if (iter && yielded) {
        // no need defer when yielded
        step.apply(self, args)
      } else {
        // need next tick if not defered
        process.nextTick(function () {
          step.apply(self, args)
        })
      }
    } else {
      step(new Error('Callback on yieldable is prohibited'))
    }
  }

  // prepend or append next arg
  if (args) opts.prepend ? args.unshift(next) : args.push(next)
  else args = [next]

  if (!isGenerator(iter)) iter = iter.apply(self, args)

  if (callback) {
    // callback mode
    step()
  } else if (opts.Promise) {
    // return promise if callback not exists
    return new opts.Promise(function (resolve, reject) {
      callback = function (err, val) {
        if (err) reject(err)
        else resolve(val)
      }
      step()
    })
  } else {
    // callback and promise not exists,
    // no try catch wrap
    trycatch = false
    callback = noop
    step()
  }
}
function _raco (iter, args, callback, opts) {
  var self = this
  var trycatch = true
  var isYieldable = true
  var yielded = false
  var nothrow = !!opts.nothrow
  /**
   * internal callback stepper
   *
   * @param {object} err - callback error object
   * @param {...*} val - callback value(s)
   */
  function step (err, val) {
    if (iter) {
      // generator step
      yielded = false
      isYieldable = false
      var state
      if (trycatch) {
        try {
          if (nothrow) state = iter.next(slice.call(arguments))
          else state = err ? iter.throw(err) : iter.next(val)
        } catch (err) {
          iter = null // catch err, break iteration
          return step(err)
        }
      } else {
        if (nothrow) state = iter.next(slice.call(arguments))
        else state = err ? iter.throw(err) : iter.next(val)
      }
      if (state && state.done) iter = null
      yielded = true
      isYieldable = yieldable.call(self, state.value, step, opts)
      if (!isYieldable && opts.yieldable) {
        isYieldable = opts.yieldable.call(self, state.value, step)
      }
      // next if generator returned non-yieldable
      if (!isYieldable && !iter) next(null, state.value)
    } else if (callback) {
      callback.apply(self, arguments)
      callback = null
    }
  }
  /**
   * next, callback stepper with nextTick
   *
   * @param {object} err - callback error object
   * @param {...*} val - callback value(s)
   */
  function next () {
    var args = slice.call(arguments)
    if (!isYieldable) {
      // only handle callback if not yieldable
      if (iter && yielded) {
        // no need defer when yielded
        step.apply(self, args)
      } else {
        // need next tick if not defered
        process.nextTick(function () {
          step.apply(self, args)
        })
      }
    } else {
      step(new Error('Callback on yieldable is prohibited'))
    }
  }

  // prepend or append next arg
  if (args) opts.prepend ? args.unshift(next) : args.push(next)
  else args = [next]

  if (!isGenerator(iter)) iter = iter.apply(self, args)

  if (callback) {
    // callback mode
    step()
  } else if (opts.Promise) {
    // return promise if callback not exists
    return new opts.Promise(function (resolve, reject) {
      callback = function (err, val) {
        if (err) reject(err)
        else resolve(val)
      }
      step()
    })
  } else {
    // callback and promise not exists,
    // no try catch wrap
    trycatch = false
    callback = noop
    step()
  }
}
function _raco ( iter , args , callback , opts ) { var self = this var trycatch = true var isYieldable = true var yielded = false var nothrow = ! ! opts . nothrow /**
   * internal callback stepper
   *
   * @param {object} err - callback error object
   * @param {...*} val - callback value(s)
   */ function step ( err , val ) { if ( iter ) { // generator step yielded = false isYieldable = false var state if ( trycatch ) { try { if ( nothrow ) state = iter . next ( slice . call ( arguments ) ) else state = err ? iter . throw ( err ) : iter . next ( val ) } catch ( err ) { iter = null // catch err, break iteration return step ( err ) } } else { if ( nothrow ) state = iter . next ( slice . call ( arguments ) ) else state = err ? iter . throw ( err ) : iter . next ( val ) } if ( state && state . done ) iter = null yielded = true isYieldable = yieldable . call ( self , state . value , step , opts ) if ( ! isYieldable && opts . yieldable ) { isYieldable = opts . yieldable . call ( self , state . value , step ) } // next if generator returned non-yieldable if ( ! isYieldable && ! iter ) next ( null , state . value ) } else if ( callback ) { callback . apply ( self , arguments ) callback = null } } /**
   * next, callback stepper with nextTick
   *
   * @param {object} err - callback error object
   * @param {...*} val - callback value(s)
   */ function next ( ) { var args = slice . call ( arguments ) if ( ! isYieldable ) { // only handle callback if not yieldable if ( iter && yielded ) { // no need defer when yielded step . apply ( self , args ) } else { // need next tick if not defered process . nextTick ( function ( ) { step . apply ( self , args ) } ) } } else { step ( new Error ( 'Callback on yieldable is prohibited' ) ) } } // prepend or append next arg if ( args ) opts . prepend ? args . unshift ( next ) : args . push ( next ) else args = [ next ] if ( ! isGenerator ( iter ) ) iter = iter . apply ( self , args ) if ( callback ) { // callback mode step ( ) } else if ( opts . Promise ) { // return promise if callback not exists return new opts . Promise ( function ( resolve , reject ) { callback = function ( err , val ) { if ( err ) reject ( err ) else resolve ( val ) } step ( ) } ) } else { // callback and promise not exists, // no try catch wrap trycatch = false callback = noop step ( ) } }
internal raco resolver

@param {function} genFn - generator function
@param {array} args - arguments in real array form
@returns {promise} if no callback provided
internal raco resolver