axios源码阅读

阅读源码分为三部

  1. 下载源码。点击查看下载链接
  2. 使用工具打开项目
  3. 睁大眼睛开始阅读

打开项目之后,我们第一步是干什么,当然是找项目入口
请看package.json的main字段指向的地址,就是项目的入口文件
axios源码阅读_第1张图片
具体看下core/axios文件有什么内容

//lib/axios.js
// 引入文件
var bind = require('./helpers/bind');
var Axios = require('./core/Axios');
var defaults = require('./defaults');
// ...省略

function createInstance(defaultConfig) {
  var context = new Axios(defaultConfig);
  // 常见的bind方法, 将request 方法的 this 指向 context
  var instance = bind(Axios.prototype.request, context);
  // ...省略
  return instance;
}

// 创建实例
var axios = createInstance(defaults);

// 允许继承
axios.Axios = Axios;

// 给实例添加一些静态方法、属性
// ...省略
axios.all = function all(promises) {
  return Promise.all(promises);
};

// 导出的是axios的实例,所以我们import的时候,可以直接使用,而不用new
module.exports = axios;
module.exports.default = axios;

可以看到,其实主要内容,是createInstance函数中的new Axios,其他的都是附加。

axios的all方法, 使用的是promise的all方法

接下来看Axios
路径是/core/Axios

// /lib/core/Axios.js
function Axios(instanceConfig) {
  this.defaults = instanceConfig;
  this.interceptors = {
    request: new InterceptorManager(),
    response: new InterceptorManager()
  };
}

Axios.prototype.request = function request(config) {
  // ...省略
};

// 为支持的请求方法提供别名
// 通过下方代码,我们可以使用axios.get(),axios.post()等方法
utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
  Axios.prototype[method] = function(url, config) {
    return this.request(utils.merge(config || {}, {
      method: method,
      url: url
    }));
  };
});
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
  Axios.prototype[method] = function(url, data, config) {
    return this.request(utils.merge(config || {}, {
      method: method,
      url: url,
      data: data
    }));
  };
});

当我们使用axios.get或者其他的方法的时候,其实使用的是Axios.prototype.request
具体来看下他干了什么

Axios.prototype.request = function request(configOrUrl, config) {
  // 定义两个收集器,收集对应的request和respont的拦截时间
  var requestInterceptorChain = [];
  var responseInterceptorChain = [];
  this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
    requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
  });
  this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
    responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
  });
  var promise;
  try {
  // 调用ajax
    promise = dispatchRequest(newConfig);
  } catch (error) {
    return Promise.reject(error);
  }
  // 并且最终返回一个promise,包含了所有的拦截器
  while (responseInterceptorChain.length) {
    promise = promise.then(responseInterceptorChain.shift(), responseInterceptorChain.shift());
  }
  return promise;
};

再来看dispatchRequest方法的实现

// lib/core/dispatchRequest.js
module.exports = function dispatchRequest(config) {
  var adapter = config.adapter || defaults.adapter;
  return adapter(config).then(/**省略**/);
};

这时候你发现,TM的再套娃。
继续往下看adapter

// lib/default/index.js
function getDefaultAdapter() {
  var adapter;
  if (typeof XMLHttpRequest !== 'undefined') {
    // 浏览器
    adapter = require('../adapters/xhr');
  } else if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {
    // node
    adapter = require('../adapters/http');
  }
  return adapter;
}
var defaults = {
  adapter: getDefaultAdapter()
  // ...省略
};
module.exports = defaults;


继续套娃,其实不算套娃,这里进行了环境区分,是浏览器还是node环境
先看浏览器

module.exports = function xhrAdapter(config) {
  // 返回promise
  return new Promise(function dispatchXhrRequest(resolve, reject) {
    // 创建对象
    var request = new XMLHttpRequest();
    // 创建链接
    request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true);
    function onloadend() {
      // settle 校验一些值
      settle(function _resolve(value) {
        resolve(value);
        done();
      }, function _reject(err) {
        reject(err);
        done();
      }, response);
    }
    if ('onloadend' in request) {
      // 无论成功还是失败
      request.onloadend = onloadend;
    } else {
      // 监听 readyState 变化
      request.onreadystatechange = function handleLoad() {
        if (!request || request.readyState !== 4) {
          return;
        }
        // readystate 在onerror和ontimeout之前就会被调用
        // 所以我们这里使用setTimeout将其放到下个tick调用
        setTimeout(onloadend);
      };
    }
    // 发送请求
    request.send(requestData);
  });
};

阅读总结:

axios在浏览器中,使用的是XMLHttpRequest

你可能感兴趣的:(面试题,JavaScript,javascript,axios,axios源码,axios原理)