🌑

秦少卫的博客

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日

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