axios源码理解

90 阅读1分钟

入行4年时间,惭愧的很,第一次看axios源码。不看不知道,一看吓一跳。不理解并且不懂大佬们的这些个想法怎么蹦跶出来的,绝了。有空可以看看axios源码

很好奇的,也是第一个惊讶的就是拦截器

添加拦截器

class InterceptorManager{
    constructor() {
        // 初始化数组
        this.handlers = [];
    }
    
    // use函数就是平常咱们使用的 
    // interceptors.request.use(func1,func2)
    // interceptors.response.use(func1,func2)
    use(fulfilled, rejected, options){
        this.handlers.push({
            // 传进来的第一个参数 key:fulfilled  value:传的第一个函数
            fulfilled,
            // 传进来的第二个参数 key:rejected  value:传的第二个函数
            rejected,
            synchronous: options ? options.synchronous : false,
            runWhen: options ? options.runWhen : null
        });
    }
}

使用拦截器

class Axios{
    // 构造函数吧
    constructor(instanceConfig) {
    this.defaults = instanceConfig;
    
    // 拦截器
    this.interceptors = {
      request: new InterceptorManager(),
      response: new InterceptorManager()
    };
  }
  
  request(configOrUrl, config){
      // ....省略逻辑
      
      // 定义请求拦截器数组
      const requestInterceptorChain = [];
      
      // 数组循环
      this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
       
      // 将拦截器中的fulfilled、rejected添加到requestInterceptorChain的  开头  unshift呀
      requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
    });
    
    // 定义响应的拦截器数组
    const responseInterceptorChain = [];
    // 数组循环
    this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
    // 将拦截器中的fulfilled、rejected添加到responseInterceptorChain的  末尾  push呀
    responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
    });
    
    
    // 核心链路
    // dispatchRequest 适配器来了  第二个惊讶的地方
    const chain = [dispatchRequest.bind(this), undefined];
    // 将请求拦截器数组添加到chain的 开头
    chain.unshift.apply(chain, requestInterceptorChain);
    // 将响应拦截器数组添加到chain的 尾部
    chain.push.apply(chain, responseInterceptorChain);
    
    // chain数组长度
    len = chain.length;

    // 构造一个promise对象
    promise = Promise.resolve(config);

    while (i < len) {
        // promise成功 执行第一个chain[i++]函数
        // 繁殖 执行第二个
        promise = promise.then(chain[i++], chain[i++]);
    }

    return promise;
    
    // ... 其他业务逻辑
  }
}

不管用get方式还是post方式、put等请求方式请求数据也好 都会执行上述request方法 接下来就是业务逻辑处理以及拦截器的调用等。dispatchRequest.bind(this) 返回一个函数,放到then方法的第一个参数上

适配器

export default function dispatchRequest(config) {
  // ... 其他业务逻辑


  // 获取自己传入的适配器或者是默认的适配器
  // 默认两种  一种http(nodejs)  一个xhr(浏览器)
  const adapter = adapters.getAdapter(config.adapter || defaults.adapter);


  // 由于adapter是一个promise对象 顾可以用then方法处理成功/失败回调
  return adapter(config).then(function onAdapterResolution(response) {
    throwIfCancellationRequested(config);

    // 响应数据转换
    response.data = transformData.call(
      config,
      config.transformResponse,
      response
    );

    response.headers = AxiosHeaders.from(response.headers);

    return response;
  }, function onAdapterRejection(reason) {
    if (!isCancel(reason)) {
      throwIfCancellationRequested(config);

      // 响应数据转换
      if (reason && reason.response) {
        reason.response.data = transformData.call(
          config,
          config.transformResponse,
          reason.response
        );
        reason.response.headers = AxiosHeaders.from(reason.response.headers);
      }
    }

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

主要看是咱们传入的适配器还是使用axios自带的默认适配器,反正我是一直用的默认适配器,返回了一个Promise对象。默认的适配器有两种,adapter: ['xhr', 'http']

http适配器

    // 判断是否是nodejs环境
    const isHttpAdapterSupported = typeof process !== 'undefined' && utils.kindOf(process) === 'process';
    
    export default isHttpAdapterSupported && function httpAdapter(config) {
        // 返回一个promise对象
        return new Promise((resolve, reject) => {
            // 业务逻辑处理...
        })
    }

xhr适配器

    // 判断是否是浏览器环境
    const isXHRAdapterSupported = typeof XMLHttpRequest !== 'undefined';
    
    export default isXHRAdapterSupported && function (config) {
        // 返回一个promise对象
        return new Promise((resolve, reject) => {
            // 业务逻辑处理...
        })
    }