axios 源码分析 - axios介绍及主文件分析

94 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情


前言

axios是前端主流的http库,基于promise,可以用在浏览器node.js中使用,本文从源码角度分析一下axios,可以让我们更好的理解和使用它。

axios的特性

  • 从浏览器中创建 XMLHttpRequests
  • 从 node.js 创建 http 请求
  • 支持 Promise API
  • 拦截请求和响应
  • 转换请求数据和响应数据
  • 取消请求
  • 自动转换 JSON 数据
  • 客户端支持防御 XSRF

示例

这里我们创建一个请求,路径是/user/,传了id12345,并且写了异步获取响应和捕获错误的方法,写法很像promise

// 为给定 ID 的 user 创建请求 
axios.get('/user?ID=12345')
    .then(function (response) { // 返回响应
        console.log(response);
    })
    .catch(function (error) { // 捕获错误
        console.log(error);
    });

目录分析

image.png

我们把项目拉下来,目录如上图,可以看到所有的主文件都在lib文件夹中,其他的都是一些示例、打包后、配置文件等。 我们把文件/文件/名翻译一下:

  • adapters/ --> 适配器
  • cancel/ --> 取消
  • core/ --> 核心
  • default/ --> 默认
  • env/ --> 环境
  • helpers/ --> 帮手
  • platform/ --> 平台
  • axios.js --> 以axios命名的应该是对外的主入口
  • utils.js --> 工具库

axios.js

开启严格模式

'use strict';

引入axios核心文件及一些工具

var utils = require('./utils'); // 工具
var bind = require('./helpers/bind'); // 绑定函数
var Axios = require('./core/Axios'); // axios主文件
var mergeConfig = require('./core/mergeConfig'); // 合并配置
var defaults = require('./defaults'); // 默认配置文件
var formDataToJSON = require('./helpers/formDataToJSON'); // formData表单转成JSON方法

定义创建实例的函数

  • 创建了一个Axios的实例,并且赋值给context变量
  • 暂时先忽略bind方法,暂时当绑定作用用,这里可以看到,Axios的原型方法request绑定了刚才创建的context变量(Axios实例),这里返回了一个新的实例给instance变量
  • 接下来通过utils.extend方法(让第三个属性继承前两个参数的属性),我们复制了第二次的实例和新的Axios原型对象的实例到第一次定义的实例上
  • 接下来把第一次的属性(context)再复制给第二次的实例上(instance)
  • 给第二次创建的实例定义了create方法,调用这个方法需要传配置参数,返回的值是该创建实例的方法,这一步用于创建实例的工厂
  • 最后返回第二次创建的实例
function createInstance(defaultConfig) {
  var context = new Axios(defaultConfig);
  var instance = bind(Axios.prototype.request, context);

  // Copy axios.prototype to instance
  utils.extend(instance, Axios.prototype, context);

  // Copy context to instance
  utils.extend(instance, context);

  // Factory for creating new instances
  instance.create = function create(instanceConfig) {
    return createInstance(mergeConfig(defaultConfig, instanceConfig));
  };

  return instance;
}

把默认参数传过去,创建axios实例并且给它增加了一些属性方法,尤其注意axios.Axios = Axios,这一步的目的是公开Axios类以允许类继承。

// 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;

结语

本文介绍了什么是axiosaxios的特性,讲了下lib文件的各个子目录的作用,对axios.js进行了逐行解析,这个文件是我们外部引用时使用的主入口,该文件创建了一个实例,并且绑定了一些方法,多处地方都是用了原型,这里需要特别注意。