Axios源码学习记录

255 阅读10分钟

入口

// 导入各种工具函数
var utils = require('./utils');
// 自定义的bind方法 该方法接收2个参数 fn和thisArg
// 返回一个wrap函数 调用该函数会调用apply方法 将fn的this指向修改为thisArg
var bind = require('./helpers/bind');
// Axios构造函数
var Axios = require('./core/Axios');
// 合并配置方法
var mergeConfig = require('./core/mergeConfig');
// 默认配置
var defaults = require('./defaults');
var formDataToJSON = require('./helpers/formDataToJSON');
/**
 * Create an instance of Axios
 *
 * @param {Object} defaultConfig The default config for the instance
 *
 * @returns {Axios} A new instance of Axios
 */
// 该方法用于创建一个Axios实例
function createInstance(defaultConfig) {
  // 使用defaultConfig创建一个axios实例
  var context = new Axios(defaultConfig);
  // 调用bind方法将Axios原型对象上定义的request方法和context传入
  // 此时instance就是一个函数
  // 一旦调用instance -> instance() 就等同于Axios.prototype.request.bind(context)()
  // 这就是为什么可以直接调用axios
  var instance = bind(Axios.prototype.request, context);
  // Copy axios.prototype to instance
  // 遍历Axios.prototype上的方法 通过bind方法绑定到instance身上 -> instance[key] = bind(Axios.prototype[key], context)
  utils.extend(instance, Axios.prototype, context);
  // Copy context to instance
  // 把context上的默认配置和请求、相应拦截器等拷贝到instance上
  utils.extend(instance, context);
  // instance = Object.assign(instance, context);
  // Factory for creating new instances
  // create方法 传入一些自定义配置,返回一个axios实例
  instance.create = function create(instanceConfig) {
    return createInstance(mergeConfig(defaultConfig, instanceConfig));
  };
  // 返回instance
  return instance;
}

// Create the default instance to be exported
var axios = createInstance(defaults);

// Expose Axios class to allow class inheritance
axios.Axios = Axios;

// Expose Cancel & CancelToken
axios.CanceledError = require('./cancel/CanceledError');
axios.CancelToken = require('./cancel/CancelToken');
axios.isCancel = require('./cancel/isCancel');
axios.VERSION = require('./env/data').version;
axios.toFormData = require('./helpers/toFormData');

// Expose AxiosError class
axios.AxiosError = require('../lib/core/AxiosError');

// alias for CanceledError for backward compatibility
axios.Cancel = axios.CanceledError;

// Expose all/spread
axios.all = function all(promises) {
  return Promise.all(promises);
};
axios.spread = require('./helpers/spread');

// Expose isAxiosError
axios.isAxiosError = require('./helpers/isAxiosError');

axios.formToJSON = function(thing) {
  return formDataToJSON(utils.isHTMLForm(thing) ? new FormData(thing) : thing);
};

module.exports = axios;


// Allow use of default import syntax in TypeScript
module.exports.default = axios;

bind方法

module.exports = function bind(fn, thisArg) {
  // 返回一个wrap函数 调用wrap相当于将fn的this指向thisArg
  return function wrap() {
    return fn.apply(thisArg, arguments);
  };
};

extend方法

function extend(a, b, thisArg) {
  // 调用forEach方法遍历bb身上的属性key复制给a 如果key的值是个函数 则指向bind方法进行this指向修改
  forEach(b, function assignValue(val, key) {
    if (thisArg && typeof val === 'function') {
      a[key] = bind(val, thisArg);
    } else {
      a[key] = val;
    }
  });
  return a;
}

核心构造函数 Axios

'use strict';

var utils = require('./../utils');
var buildURL = require('../helpers/buildURL');
var InterceptorManager = require('./InterceptorManager');
var dispatchRequest = require('./dispatchRequest');
var mergeConfig = require('./mergeConfig');
var buildFullPath = require('./buildFullPath');
var validator = require('../helpers/validator');

var validators = validator.validators;
/**
 * Create a new instance of Axios
 *
 * @param {Object} instanceConfig The default config for the instance
 *
 * @return {Axios} A new instance of Axios
 */
function Axios(instanceConfig) {
  // 定义默认配置
  this.defaults = instanceConfig;
  // 初始化请求截器和响应拦截器
  this.interceptors = {
    request: new InterceptorManager(),
    response: new InterceptorManager()
  };
}

/**
 * Dispatch a request
 *
 * @param {String|Object} configOrUrl The config specific for this request (merged with this.defaults)
 * @param {?Object} config
 *
 * @returns {Promise} The Promise to be fulfilled
 */
// 真正的发送请求的方法
Axios.prototype.request = function request(configOrUrl, config) {
  /*eslint no-param-reassign:0*/
  // Allow for axios('example/url'[, config]) a la fetch API
  // 如果configOrUrl是字符串 则说明是这样调用的 axios('xxx',{})
  if (typeof configOrUrl === 'string') {
    // config等于config || {}
    config = config || {};
    // config.url = configOrUrl
    config.url = configOrUrl;
  } else {
    // 否则 有可能是这样调用的 axios({url:'xxx'})
    config = configOrUrl || {};
  }
  // 合并默认配置和用户自定义配置
  config = mergeConfig(this.defaults, config);

  // Set config.method
  // 设置 请求方法,默认 get
  if (config.method) {
    config.method = config.method.toLowerCase();
  } else if (this.defaults.method) {
    config.method = this.defaults.method.toLowerCase();
  } else {
    config.method = 'get';
  }

  var transitional = config.transitional;

  if (transitional !== undefined) {
    validator.assertOptions(
      transitional,
      {
        silentJSONParsing: validators.transitional(validators.boolean),
        forcedJSONParsing: validators.transitional(validators.boolean),
        clarifyTimeoutError: validators.transitional(validators.boolean)
      },
      false
    );
  }
  // filter out skipped interceptors
  // 定义请求拦截器数组
  var requestInterceptorChain = [];
  var synchronousRequestInterceptors = true;
  // 调用请求拦截器的forEach方法 该方法会遍历请求拦截器的handlers数组 并执行传入的函数 例如下面的unshiftRequestInterceptors方法
  this.interceptors.request.forEach(function unshiftRequestInterceptors(
    interceptor
  ) {
    if (
      typeof interceptor.runWhen === 'function' &&
      interceptor.runWhen(config) === false
    ) {
      return;
    }
    synchronousRequestInterceptors =
      synchronousRequestInterceptors && interceptor.synchronous;
    // interceptor是一个对象 {
    //   fulfilled: fulfilled,
    //   rejected: rejected,
    //   synchronous: options ? options.synchronous : false,
    //   runWhen: options ? options.runWhen : null
    // }
    // 将interceptor的fulfilled和rejected方法添加到requestInterceptorChain头部
    // 因为调用的是unshift 所以先定义的请求拦截器后执行
    requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
  });
  // 定义响应拦截器数组
  var responseInterceptorChain = [];
  this.interceptors.response.forEach(function pushResponseInterceptors(
    interceptor
  ) {
    // 将interceptor的fulfilled和rejected方法添加到requestInterceptorChain尾部
    // 因为调用的是push 所以先定义的响应拦截器先执行
    responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
  });
  var promise;
  // 若需要异步执行,则异步执行拦截器数组
  if (!synchronousRequestInterceptors) {
    // 组成Promise调用链
    // 把 xhr 请求 的 dispatchRequest 和 undefined 放在一个数组里 方便后面调用
    var chain = [dispatchRequest, undefined];
    // 将requestInterceptorChain添加到chain的头部
    Array.prototype.unshift.apply(chain, requestInterceptorChain);
    // 将responseInterceptorChain添加到chain的尾部
    chain = chain.concat(responseInterceptorChain);
    // 创建 一个resolve(config)的Promise 实例 此时通过then方法拿到的值就是config
    promise = Promise.resolve(config);
    // 遍历chain 挨个执行拦截器中的fulfilled和rejected函数
    while (chain.length) {
      promise = promise.then(chain.shift(), chain.shift());
    }
    // 返回promise 所以用户可以axios().then()调用
    return promise;
  }
  // 否则同步执行请求拦截器,直到拦截器栈清空
  var newConfig = config;
  // 先执行请求拦截器
  while (requestInterceptorChain.length) {
    // 成功的回调
    var onFulfilled = requestInterceptorChain.shift();
    // 失败的回调
    var onRejected = requestInterceptorChain.shift();
    try {
      // 获取请求拦截器处理后的config 这就是为什么onFulfilled要返回config
      newConfig = onFulfilled(newConfig);
    } catch (error) {
      // 一旦走到失败回调 直接break
      onRejected(error);
      break;
    }
  }
  // 再发送请求
  try {
    // 真正开始发送请求 将请求拦截器处理后的config传递给dispatchRequest
    promise = dispatchRequest(newConfig);
  } catch (error) {
    return Promise.reject(error);
  }
  // 最后再执行响应拦截器
  while (responseInterceptorChain.length) {
    promise = promise.then(
      responseInterceptorChain.shift(),
      responseInterceptorChain.shift()
    );
  }
  // 返回promise 所以用户可以axios().then()调用
  return promise;
};
// 获取最终请求的uri
Axios.prototype.getUri = function getUri(config) {
  config = mergeConfig(this.defaults, config);
  var fullPath = buildFullPath(config.baseURL, config.url);
  return buildURL(fullPath, config.params, config.paramsSerializer);
};
// 将'delete', 'get', 'head', 'options'等方法添加到Axios.prototype上 本质是还是调用request方法
// Provide aliases for supported request methods
utils.forEach(
  ['delete', 'get', 'head', 'options'],
  function forEachMethodNoData(method) {
    /*eslint func-names:0*/
    Axios.prototype[method] = function(url, config) {
      return this.request(
        mergeConfig(config || {}, {
          method: method,
          url: url,
          data: (config || {}).data
        })
      );
    };
  }
);
// 将'post', 'put', 'patch'等方法添加到Axios.prototype上 本质是还是调用request方法
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
  /*eslint func-names:0*/

  function generateHTTPMethod(isForm) {
    return function httpMethod(url, data, config) {
      return this.request(
        mergeConfig(config || {}, {
          method: method,
          // 判断是否是提交表单数据
          headers: isForm
            ? {
              'Content-Type': 'multipart/form-data'
            }
            : {},
          url: url,
          data: data
        })
      );
    };
  }
  // 调用一下generateHTTPMethod方法 返回httpMethod方法
  Axios.prototype[method] = generateHTTPMethod();
  // 调用一下generateHTTPMethod方法
  Axios.prototype[method + 'Form'] = generateHTTPMethod(true);
});

module.exports = Axios;

拦截器InterceptorManager

'use strict';

var utils = require('./../utils');

function InterceptorManager() {
  // 拦截器数组
  this.handlers = [];
}

/**
 * Add a new interceptor to the stack
 *
 * @param {Function} fulfilled The function to handle `then` for a `Promise`
 * @param {Function} rejected The function to handle `reject` for a `Promise`
 *
 * @return {Number} An ID used to remove interceptor later
 */
// 添加拦截器
InterceptorManager.prototype.use = function use(fulfilled, rejected, options) {
  // fulfilled 成功的回调函数
  // rejected 失败的回调函数
  this.handlers.push({
    fulfilled: fulfilled,
    rejected: rejected,
    synchronous: options ? options.synchronous : false,
    runWhen: options ? options.runWhen : null
  });
  // 返回索引
  return this.handlers.length - 1;
};

/**
 * Remove an interceptor from the stack
 *
 * @param {Number} id The ID that was returned by `use`
 *
 * @returns {Boolean} `true` if the interceptor was removed, `false` otherwise
 */
// 移除拦截器
InterceptorManager.prototype.eject = function eject(id) {
  // 根据id找到拦截器,这里并没有直接删除,而是赋值为null 是为了防止id错乱
  if (this.handlers[id]) {
    this.handlers[id] = null;
  }
};

/**
 * Clear all interceptors from the stack
 *
 * @returns {void}
 */
// 清空拦截器
InterceptorManager.prototype.clear = function clear() {
  if (this.handlers) {
    this.handlers = [];
  }
};

/**
 * Iterate over all the registered interceptors
 *
 * This method is particularly useful for skipping over any
 * interceptors that may have become `null` calling `eject`.
 *
 * @param {Function} fn The function to call for each interceptor
 *
 * @returns {void}
 */
//  遍历handlers,传递一个回调函数(handlers中每一项作为函数的参数调用)
InterceptorManager.prototype.forEach = function forEach(fn) {
  utils.forEach(this.handlers, function forEachHandler(h) {
    if (h !== null) {
      fn(h);
    }
  });
};

module.exports = InterceptorManager;

dispatchRequest

'use strict';

var utils = require('./../utils');
var transformData = require('./transformData');
var isCancel = require('../cancel/isCancel');
var defaults = require('../defaults');
var CanceledError = require('../cancel/CanceledError');
var normalizeHeaderName = require('../helpers/normalizeHeaderName');

/**
 * Throws a `CanceledError` if cancellation has been requested.
 *
 * @param {Object} config The config that is to be used for the request
 *
 * @returns {void}
 */
// 抛出 错误原因,使`Promise`走向`rejected`
function throwIfCancellationRequested(config) {
  if (config.cancelToken) {
    config.cancelToken.throwIfRequested();
  }

  if (config.signal && config.signal.aborted) {
    throw new CanceledError();
  }
}

/**
 * Dispatch a request to the server using the configured adapter.
 *
 * @param {object} config The config that is to be used for the request
 *
 * @returns {Promise} The Promise to be fulfilled
 */
module.exports = function dispatchRequest(config) {
  throwIfCancellationRequested(config);

  // 确保 headers 存在
  // Ensure headers exist
  config.headers = config.headers || {};

  // Transform request data
  // 转换请求的数据
  config.data = transformData.call(
    config,
    config.data,
    config.headers,
    null,
    config.transformRequest
  );
  // 拍平 headers
  normalizeHeaderName(config.headers, 'Accept');
  normalizeHeaderName(config.headers, 'Content-Type');

  // Flatten headers
  config.headers = utils.merge(
    config.headers.common || {},
    config.headers[config.method] || {},
    config.headers
  );
  // 以下这些方法 删除 headers
  utils.forEach(
    ['delete', 'get', 'head', 'post', 'put', 'patch', 'common'],
    function cleanHeaderConfig(method) {
      delete config.headers[method];
    }
  );
  // 适配器模式 一般是调用xhrAdapter 这里才是真正的发送网络请求的地方
  var adapter = config.adapter || defaults.adapter;
  // 调用adapter 传入config adapter返回一个promise 在adapter使用Promise包裹一个XMLHttpRequest请求,如果成功则resolve 失败则reject
  return adapter(config).then(function onAdapterResolution(response) {
    throwIfCancellationRequested(config);
    // 转换响应的数据
    // Transform response data
    response.data = transformData.call(
      config,
      response.data,
      response.headers,
      response.status,
      config.transformResponse
    );
    // 返回response
    return response;
  }, function onAdapterRejection(reason) {
    if (!isCancel(reason)) {
      throwIfCancellationRequested(config);

      // Transform response data
      if (reason && reason.response) {
        reason.response.data = transformData.call(
          config,
          reason.response.data,
          reason.response.headers,
          reason.response.status,
          config.transformResponse
        );
      }
    }

    return Promise.reject(reason);
  });
};


xhrAdapter

'use strict';

var utils = require('./../utils');
var settle = require('./../core/settle');
var cookies = require('./../helpers/cookies');
var buildURL = require('./../helpers/buildURL');
var buildFullPath = require('../core/buildFullPath');
var parseHeaders = require('./../helpers/parseHeaders');
var isURLSameOrigin = require('./../helpers/isURLSameOrigin');
var transitionalDefaults = require('../defaults/transitional');
var AxiosError = require('../core/AxiosError');
var CanceledError = require('../cancel/CanceledError');
var parseProtocol = require('../helpers/parseProtocol');
var platform = require('../platform');

module.exports = function xhrAdapter(config) {
  // 返回一个promise
  return new Promise(function dispatchXhrRequest(resolve, reject) {
    var requestData = config.data;
    var requestHeaders = config.headers;
    var responseType = config.responseType;
    var onCanceled;
    // 请求完成后取消cancelToken订阅事件
    function done() {
      if (config.cancelToken) {
        config.cancelToken.unsubscribe(onCanceled);
      }

      if (config.signal) {
        config.signal.removeEventListener('abort', onCanceled);
      }
    }

    if (utils.isFormData(requestData) && utils.isStandardBrowserEnv()) {
      delete requestHeaders['Content-Type']; // Let the browser set it
    }
    // 创建一个XMLHttpRequest对象 开始发送请求
    var request = new XMLHttpRequest();

    // HTTP basic authentication
    if (config.auth) {
      var username = config.auth.username || '';
      var password = config.auth.password ? unescape(encodeURIComponent(config.auth.password)) : '';
      requestHeaders.Authorization = 'Basic ' + btoa(username + ':' + password);
    }

    var fullPath = buildFullPath(config.baseURL, config.url);
    // 调用open方法
    request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true);
    // 设置超时时间
    // Set the request timeout in MS
    request.timeout = config.timeout;

    function onloadend() {
      if (!request) {
        return;
      }
      // Prepare the response
      var responseHeaders = 'getAllResponseHeaders' in request ? parseHeaders(request.getAllResponseHeaders()) : null;
      var responseData = !responseType || responseType === 'text' ||  responseType === 'json' ?
        request.responseText : request.response;
      var response = {
        data: responseData,
        status: request.status,
        statusText: request.statusText,
        headers: responseHeaders,
        config: config,
        request: request
      };

      settle(function _resolve(value) {
        resolve(value);
        done();
      }, function _reject(err) {
        reject(err);
        done();
      }, response);

      // Clean up request
      request = null;
    }

    if ('onloadend' in request) {
      // Use onloadend if available
      request.onloadend = onloadend;
    } else {
      // Listen for ready state to emulate onloadend
      request.onreadystatechange = function handleLoad() {
        if (!request || request.readyState !== 4) {
          return;
        }

        // The request errored out and we didn't get a response, this will be
        // handled by onerror instead
        // With one exception: request that using file: protocol, most browsers
        // will return status as 0 even though it's a successful request
        if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf('file:') === 0)) {
          return;
        }
        // readystate handler is calling before onerror or ontimeout handlers,
        // so we should call onloadend on the next 'tick'
        setTimeout(onloadend);
      };
    }

    // Handle browser request cancellation (as opposed to a manual cancellation)
    // 注册取消请求处理函数
    request.onabort = function handleAbort() {
      if (!request) {
        return;
      }

      reject(new AxiosError('Request aborted', AxiosError.ECONNABORTED, config, request));

      // Clean up request
      request = null;
    };

    // Handle low level network errors
    // 注册请求失败处理函数
    request.onerror = function handleError() {
      // Real errors are hidden from us by the browser
      // onerror should only fire if it's a network error
      reject(new AxiosError('Network Error', AxiosError.ERR_NETWORK, config, request));

      // Clean up request
      request = null;
    };

    // Handle timeout
    // 注册请求超时处理函数
    request.ontimeout = function handleTimeout() {
      var timeoutErrorMessage = config.timeout ? 'timeout of ' + config.timeout + 'ms exceeded' : 'timeout exceeded';
      var transitional = config.transitional || transitionalDefaults;
      if (config.timeoutErrorMessage) {
        timeoutErrorMessage = config.timeoutErrorMessage;
      }
      reject(new AxiosError(
        timeoutErrorMessage,
        transitional.clarifyTimeoutError ? AxiosError.ETIMEDOUT : AxiosError.ECONNABORTED,
        config,
        request));

      // Clean up request
      request = null;
    };

    // Add xsrf header
    // This is only done if running in a standard browser environment.
    // Specifically not if we're in a web worker, or react-native.
    if (utils.isStandardBrowserEnv()) {
      // Add xsrf header
      var xsrfValue = (config.withCredentials || isURLSameOrigin(fullPath)) && config.xsrfCookieName ?
        cookies.read(config.xsrfCookieName) :
        undefined;

      if (xsrfValue) {
        requestHeaders[config.xsrfHeaderName] = xsrfValue;
      }
    }

    // Add headers to the request
    if ('setRequestHeader' in request) {
      utils.forEach(requestHeaders, function setRequestHeader(val, key) {
        if (typeof requestData === 'undefined' && key.toLowerCase() === 'content-type') {
          // Remove Content-Type if data is undefined
          delete requestHeaders[key];
        } else {
          // Otherwise add header to the request
          request.setRequestHeader(key, val);
        }
      });
    }

    // Add withCredentials to request if needed
    if (!utils.isUndefined(config.withCredentials)) {
      request.withCredentials = !!config.withCredentials;
    }

    // Add responseType to request if needed
    if (responseType && responseType !== 'json') {
      request.responseType = config.responseType;
    }
    // 监听下载进度
    // Handle progress if needed
    if (typeof config.onDownloadProgress === 'function') {
      request.addEventListener('progress', config.onDownloadProgress);
    }
    // 监听上传进度
    // Not all browsers support upload events
    if (typeof config.onUploadProgress === 'function' && request.upload) {
      request.upload.addEventListener('progress', config.onUploadProgress);
    }
    // 取消请求相关 判断如果有cancelToken
    if (config.cancelToken || config.signal) {
      // Handle cancellation
      // eslint-disable-next-line func-names
      // 定义一个onCanceled方法 接收一个cancel变量 如果这次请求被取消了 cancel就是取消的reason
      onCanceled = function(cancel) {
        if (!request) {
          return;
        }
        // 直接reject这次promise reject的原因就是cancel 如果没有cancel 或者cancel.type 则new一个CanceledError
        reject(!cancel || cancel.type ? new CanceledError(null, config, req) : cancel);
        // 调用abort方法取消XMLHttpRequest请求
        request.abort();
        request = null;
      };
      // 调用cancelToken的subscribe方法订阅nCanceled
      config.cancelToken && config.cancelToken.subscribe(onCanceled);
      if (config.signal) {
        config.signal.aborted ? onCanceled() : config.signal.addEventListener('abort', onCanceled);
      }
    }

    if (!requestData) {
      requestData = null;
    }

    var protocol = parseProtocol(fullPath);

    if (protocol && platform.protocols.indexOf(protocol) === -1) {
      reject(new AxiosError('Unsupported protocol ' + protocol + ':', AxiosError.ERR_BAD_REQUEST, config));
      return;
    }

    // Send the request
    request.send(requestData);
  });
};

CancelToken

'use strict';

var CanceledError = require('./CanceledError');

/**
 * A `CancelToken` is an object that can be used to request cancellation of an operation.
 *
 * @param {Function} executor The executor function.
 *
 * @returns {CancelToken}
 */
function CancelToken(executor) {
  // 接收一个executor函数
  if (typeof executor !== 'function') {
    throw new TypeError('executor must be a function.');
  }
  // 定义一个resolvePromise变量
  var resolvePromise;
  // 初始化一个promise
  this.promise = new Promise(function promiseExecutor(resolve) {
    // 将该promise的resolve方法赋值给resolvePromise
    // 一旦调用resolvePromise this.promise的状态就会被修改为fuifulled
    resolvePromise = resolve;
  });
  // 将this赋值给token
  var token = this;

  // eslint-disable-next-line func-names
  this.promise.then(function(cancel) {
    if (!token._listeners) return;

    var i = token._listeners.length;

    while (i-- > 0) {
      token._listeners[i](cancel);
    }
    token._listeners = null;
  });

  // eslint-disable-next-line func-names
  this.promise.then = function(onfulfilled) {
    var _resolve;
    // eslint-disable-next-line func-names
    var promise = new Promise(function(resolve) {
      token.subscribe(resolve);
      _resolve = resolve;
    }).then(onfulfilled);

    promise.cancel = function reject() {
      token.unsubscribe(_resolve);
    };

    return promise;
  };
  // new CancelToken时会立即调用executor方法 也就是会执行source方法中的cancel = c;
  // 这里也就是把cancel函数暴露出去了,把取消的时机留给了使用者 使用者调用cancel时候也就会执行函数内的逻辑
  // 一旦调用cancel this.promise的状态就变成了fulfulled
  executor(function cancel(message, config, request) {
    // 请求已经被取消了直接return
    if (token.reason) {
      // Cancellation has already been requested
      return;
    }

    token.reason = new CanceledError(message, config, request);
    resolvePromise(token.reason);
  });
}

/**
 * Throws a `CanceledError` if cancellation has been requested.
 */
CancelToken.prototype.throwIfRequested = function throwIfRequested() {
  if (this.reason) {
    throw this.reason;
  }
};

/**
 * Subscribe to the cancel signal
 */

CancelToken.prototype.subscribe = function subscribe(listener) {
  if (this.reason) {
    listener(this.reason);
    return;
  }

  if (this._listeners) {
    this._listeners.push(listener);
  } else {
    this._listeners = [listener];
  }
};

/**
 * Unsubscribe from the cancel signal
 */

CancelToken.prototype.unsubscribe = function unsubscribe(listener) {
  if (!this._listeners) {
    return;
  }
  var index = this._listeners.indexOf(listener);
  if (index !== -1) {
    this._listeners.splice(index, 1);
  }
};

/**
 * Returns an object that contains a new `CancelToken` and a function that, when called,
 * cancels the `CancelToken`.
 */
// 返回一个对象 token就是CancelToken实例 实例上有两个属性一个promise一个reason
//  cancel就是CancelToken内部传递给外部的cancel函数
CancelToken.source = function source() {
  var cancel;
  var token = new CancelToken(function executor(c) {
    cancel = c;
  });
  return {
    token: token,
    cancel: cancel
  };
};

module.exports = CancelToken;

部分内容参考了lxchuan12.gitee.io/axios 目前只看了这么多,cancelToken只能看个大概,太复杂了╥﹏╥