🌑

秦少卫的博客

Axios源码学习

目录

  1. 介绍
  2. 初始化:axios 、Axios、intance
  3. 整体流程:request => deispatchRequest => Adapter
  4. 数据转换:despatchRequest
  5. 适配器:Adapter
  6. 拦截器:request => deispatchRequest => response
  7. 取消请求:cancelToken => adapter => cancel
  8. 回顾

介绍

特点:

  1. 支持浏览器与Node.js
  2. API promise
  3. 请求/响应拦截器
  4. 请求/响应格式化方法
  5. 取消请求

用法:

// 直接发送请求
axios(config)
axios(url[, config])
axios.request(config)

// 别名方法
axios.get(url[, config])
axios.delete(url[, config])
axios.post(url[, data, config])
axios.put(url[, data, config])

axios.defaults.xxx: 请求的默认全局配置 
axios.interceptors.request.use(): 添加请求拦截器 
axios.interceptors.response.use(): 添加响应拦截器

axios.create([config]): 创建一个新的 axios

// 只有默认axios有的方法,新创建的没有
axios.Cancel(): 用于创建取消请求的错误对象 
axios.CancelToken(): 用于创建取消请求的 token 对象 
axios.isCancel(): 是否是一个取消请求的错误 
axios.all(promises): 用于批量执行多个异步请求 
axios.spread(): 

​

目录结构

├── adapters
│   ├── README.md
│   ├── http.js   // Node环境请求
│   └── xhr.js    // 浏览器环境请求
├── axios.js      // 入口文件 初始化
├── cancel        // 请求取消模块
│   ├── Cancel.js  
│   ├── CancelToken.js
│   └── isCancel.js
├── core          // 核心模块
│   ├── Axios.js  // 初始化
│   ├── InterceptorManager.js   // 拦截器管理
│   ├── buildFullPath.js
│   ├── createError.js
│   ├── dispatchRequest.js       // 请求调用
│   ├── enhanceError.js
│   ├── mergeConfig.js
│   ├── settle.js
│   └── transformData.js         // 数据转换
├── defaults.js                  // 默认配置
├── env
│   ├── README.md
│   └── data.js
├── helpers
│   ├── README.md
│   ├── bind.js                  // bind
│   ├── buildURL.js
│   ├── combineURLs.js
│   ├── cookies.js
│   ├── deprecatedMethod.js
│   ├── isAbsoluteURL.js
│   ├── isAxiosError.js
│   ├── isURLSameOrigin.js
│   ├── normalizeHeaderName.js
│   ├── parseHeaders.js
│   ├── spread.js
│   └── validator.js
└── utils.js          // 类型判断、对象方法(forEach、merge、extend)

​

初始化

带着这个问题开始 axios与Axios的关系?
入口文件lib/axios.js,通过 工厂函数 createInstance 初始化,得到axios,并给axios挂载Cancel、CancelToken等方法。
image.png

​

初始化的流程开始从工厂函数 createInstance开始:

  1. Axios构造函数生成对象带有defaults属性和拦截器属性的对象
  2. bind(request, content) 返回一个闭包的request方法。
  3. 拷贝Axios.prototype(get/post/request)
  4. 拷贝context上的 defaults 和 拦截器属性。

image.png
​

逐行分析 + debugger:

  1. Axios构造函数生成对象带有defaults属性和拦截器属性的对象

  2. bind(request, content) 返回一个闭包的request方法。

    var context = new Axios(defaultConfig);
    var instance = bind(Axios.prototype.request, context);

    image.png

  3. 拷贝Axios.prototype(get/post/request)

    utils.extend(instance, Axios.prototype, context);

    image.png

​

  1. 拷贝context上的 defaults 和 拦截器属性。

image.png

Axios构造函数:
delete、get等方法都是request的别名,只不过是合并了一下不同的配置config配置。
image.png

axios 与 Axios 的关系

  1. 语法上:axios 不是Axios的对象实例
  2. 功能上:axios 具备 Axios实例上的所有功能(方法:Axios.porotype、属性:defaults/interceptors)
  3. axios 是 Axios.porotype.request 函数 bind返回的 warp 函数,可直接使用。

axios.created 创建的对象 与 axios 的区别

相同:直接发送请求、具有request、get/post方法,具有defaults/interceptors属性。
不同:新的instance 不具有 Cancel、CancelToken方法。

image.png

15

整体流程

责任链模式

行为模式负责对象间的高效沟通和职责委派。
​

责任链模式是一种行为设计模式, 允许你将请求沿着处理者链进行发送。 收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。

image.png

模块流程:
Axios.porotype.request(config) ==> despatchRequest(config) ==> adapter(config)
image.png
​

重要模块与职责:

  1. request: 请求拦截 => despatchRequest => 响应拦截,通过promise串联
  2. despatchRequest: 请求数据转换 => adapter => 响应数据转换
  3. adpter:根据环境确定请求函数 返回promise

整体流程:
image.png
​

​

转换数据 despatchRequest

image.png
​

image.png
image.png
​

默认转换
image.png
​

适配器

结构型模式介绍如何将对象和类组装成较大的结构, 并同时保持结构的灵活和高效。
适配器模式是一种结构型设计模式, 它能使接口不兼容的对象能够相互合作。

​

image.png

image.png
image.png

拦截器

image.png

拦截器管理

取消拦截器?
拦截器执行顺序?
image.png

lib/core/InterceptorManager.js

  • user:添加
  • eject:删除
  • forEach:获取所有

image.png

添加/取消拦截器
image.png
​

​

lib/core/Axios.js Axios.prototype.request
image.png

异步执行

image.png
image.png

同步执行

image.png
image.png

执行顺序

image.png
image.png

写一个demo

const config = {a:'111'}
const promise = Promise.resolve(config);
const arr = [promise]
let resault = promise

arr.push((config) => {
    config['user1'] = 111
    console.log(config, '111')
    return config
})

arr.push((config) => {
    config['user2'] = 2222
    console.log(config, '222')
    return config
})

arr.push((config) => {
    config['user3'] = 3333
    console.log(config, '333')
    return config
})

while (arr.length) {
    resault = promise.then(arr.shift())
}

image.png

取消请求

取消的使用

image.png
​

lib/cancel/CancelToken.js 主函数与subscribe
image.png

订阅函数
image.png
​

第一步 生成
cancelToken = new axios.CancelToken(c => cancel = c)
image.png
​

第二步
xhr内 cancelToken.subscribe 存储取消事件
image.png
image.png
​

第三步
执行通过subscribe存储的取消事件
image.png

image.png
​

观察者模式

观察者模式是一种行为设计模式, 允许你定义一种订阅机制, 可在对象事件发生时通知多个 “观察” 该对象的其他对象。

image.png
​

​

观察者模式与发布订阅的关系 讨论?
观察者模式包含发布订阅。
发布订阅是观察者的升级变种。
观察者模式与发布订阅的区别是否有事件调度中心。
image.png

回顾

  1. axios 、Axios 的区别、初始化流程
  2. config责任链,关键模块 request、despatchRequest、adpter 的职责, 请求整体流程。
  3. despatchRequest的default转换 自动转json
  4. 适配器实现
  5. request 拦截器实现,取消拦截器、执行顺序。
  6. 取消请求的实现

​

感悟:

  • 模块职责清晰
  • 适配器易扩展
  • 拦截器、格式转换灵活
  • 设计模式的分类:创建型、结构型、行为型
  • 技巧与方法 && 持续学习

— 2021年11月22日

静水流深,闻喧享静。空山鸣响,见惯司空。