docs: function _fetch (instance, document, options, callbackId, progressCallbackId) {
    const config = clonePlainObject(options)
  
    // validate options.method
    if (typeof config.method === 'undefined') {
      config.method = DEFAULT_METHOD
    }
    else if (methodOptions.indexOf((config.method + '')
        .toUpperCase()) === -1) {
      return console.error(`[stream] options.method "${config.method}" for "fetch" API should be one of ${methodOptions}.`)
    }
  
    // validate options.url
    if (!config.url) {
      return console.error(`[stream] options.url should be set for "fetch" API.`)
    }
  
    // validate options.mode
    if (typeof config.mode === 'undefined') {
      config.mode = DEFAULT_MODE
    }
    else if (modeOptions.indexOf((config.mode + '').toLowerCase()) === -1) {
      return console.error(`[stream] options.mode "${config.mode}" for "fetch" API should be one of ${modeOptions}.`)
    }
  
    // validate options.type
    if (typeof config.type === 'undefined') {
      config.type = DEFAULT_TYPE
    }
    else if (typeOptions.indexOf((config.type + '').toLowerCase()) === -1) {
      return console.error(`[stream] options.type "${config.type}" for "fetch" API should be one of ${typeOptions}.`)
    }
  
    // validate options.headers
    config.headers = config.headers || {}
    if (!config.headers) {
      return console.error(`[stream] options.headers should be a plain object.`)
    }
  
    // validate options.body
    const body = config.body
    if (!config.headers['Content-Type'] && body) {
      if (body) {
        // is a json data
        try {
          config.body = JSON.stringify(body)
          config.headers['Content-Type'] = TYPE_JSON
        }
        catch (e) {}
      }
      else if (typeof body === 'string' && body.match(REG_FORM)) {
        // is form-data
        config.body = encodeURI(body)
        config.headers['Content-Type'] = TYPE_FORM
      }
    }
  
    // validate options.timeout
    config.timeout = parseInt(config.timeout, 10) || 2500
  
    const _callArgs = [config, function (res) {
      instance.$callback(callbackId, res, false)
    }]
    if (progressCallbackId) {
      _callArgs.push(function (res) {
        // Set 'keepAlive' to true for sending continuous callbacks
        instance.$callback(progressCallbackId, res, true)
      })
    }
  
    if (config.type === 'jsonp') {
      _jsonp.apply(this, _callArgs)
    }
    else {
      _xhr.apply(this, _callArgs)
    }
  }