Axios源码解读

为何要阅读源码?用尤大的话:提升自己的行业竞争力。本文以Axios为例,带你一下学习源码。之所以选择Axios,因为它是一款非常流行的处理http请求的库,前端几乎人人在用,复杂度适中且有很好的注释解释。

姿势很重要

正式开始前,先普及一下源码阅读的正确姿势:

  • Github fork一个你想学习的项目(如果你不知道Github,那你不用往下看了)
  • 在fork的项目下建一个学习分支
  • 熟悉、理解项目结构
  • 开始阅读(最好遵循一定的顺序)
  • 在源代码里添加你自己的理解或标记
  • 提交学习记录到学习分支

再有,就是要有一个平常的心态,没有人天生就是代码高手;同时要有正确的学习理念,那就是:

  • 你是学习人家的设计思想,而不是全盘吸收,这玩意真不值得你全部背下来
  • 对于那些非常巧妙的点,一定要重点关注,确保理解和吸收。
  • 做一些练习巩固你的理解

好,你准备好了吗?进入正题!

先别慌,瞄一眼很重要

先看他的package.json文件,了解两个关键信息:

  • 入口文件是index.js
  • 打包命令是npm run build

image.png

打开terminal键入命令npm installnpm run build

然后进入dist目录查看axios.js文件:

image.png
这是最后一行的行号–2297,其实我想说非压缩的版本只有2000多行,所以确实不复杂,我没骗你的!

其次再瞄一眼目录结构:

image.png

lib目录是存放源码的,像其他目录如 examplessandboxtest等是起辅助作用的,dist是编译包的存放目录,所以我们主要关注的部分将是lib目录。

ok,瞄完了!
所以我们知道了应该从入口index.js开始,源码都在lib目录,不懂可以看注释文档或README.md

从入口文件开始

入口文件内容很直接:module.exports = require('./lib/axios');,所以间接入口是lib目录下的axios.js
内容也很简单:

  • 创建一个Axios的实例
  • 往上面挂几个方法或属性
  • 返回该实例
'use strict';
//引入省略。。。

/**
 * Create an instance of Axios
 *
 * @param {Object} defaultConfig The default config for the instance
 * @return {Axios} A new instance of Axios
 */
 
// 创建Axios的一个实例的工厂函数
function createInstance(defaultConfig) {
     
  //省略了
}

// 执行示例创建
// Create the default instance to be exported
var axios = createInstance(defaults);

// 暴露自己的爹
axios.Axios = Axios;

// 把创建自己的工厂函数也暴露出去
axios.create = function create(instanceConfig) {
   
  return createInstance(mergeConfig(axios.defaults, instanceConfig));
};

// 挂载几个有用的方法
// 省略。。。
axios.xxx = yyyy;

// 最后导出,o了
module.exports = axios;

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

现在,你明白了Axios实例是通过createInstance()创建的,可以通过axios.create()间接调用它,并且该库的作者非常贴心,默认为你创建好并导出了,你直接 require('axios')就可以使用了。

这样阅读是不是有点走马观花?我觉得一点也不,这里不值得我们下狠功夫!

请求是如何发起的?

我们知道,可以通过调用axios.get|post发起请求,然后处理返回的promise对象即可对响应的数据做处理。那么,这一切的背后原理是怎样的?

首先这些方法在哪里定义?Axios原型对象:

// lib/core/Axios.js
// 遍历方法数组给原型对象添加方法
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
    }));
  };
});

// 遍历方法数组给原型对象添加方法
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
   
  /*eslint func-names:0*/
  Axios.prototype[method] = function(url, data, config) {
   
    return this.request(mergeConfig(config || {
   }, {
   
      method: method,
      url: url,
      data: data
    }));
  };
});

接着我们看到会返回this.request函数的调用返回值,它当然是一个promise对象:

/**
 * Dispatch a request
 *
 * @param {Object} config The config specific for this request (merged with this.defaults)
 */
Axios.prototype.request = function request(config) {
   

  // 省略了无数行,这里他们不重要
  
  try {
   
    //创建请求的promsie对象
    promise = dispatchRequest(newConfig);
  } catch (error) {
   
    return Promise.reject(error);
  }
  
  // 省略了无数行,这里他们不重要
  
  //返回一个promise对象
  return promise;
};

所以我们断定dispatchRequest这哥们是个关键角色:

/**
 * 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) {
   

  // 省略了无数行  
  
  // 获取adapter
  var adapter 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值