手写axios源码系列一:axios核心知识点

这篇具有很好参考价值的文章主要介绍了手写axios源码系列一:axios核心知识点。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

手写axios源码系列一:axios核心知识点

最近从头搭建了一个vue小项目,想使用 axios 作为请求接口的第三方库。结果使用了 axios 这么长时间,想封装一下 axios ,也就是大部分项目中的 src/utils/request.js文件,我居然无法默写出来,create 和 interceptors 这样的 api 都不知道怎么使用;所以决定深入一下 axios 源码,一探究竟 axios 到底是个什么东东。

当前 axios 源码版本为"axios": "^1.3.5"

axios的核心功能

1、axios 函数对象

为什么在这里叫 axios 函数对象

这是因为在 JavaScript 中,函数也是对象,也可以挂载属性以及方法。俗话说:一切皆是对象。

axios使用方式:

  • axios({ method: "post" })
  • axios.post()

由 axios 的使用方式可知,axios 既可以被调用,也可以使用对象的点语法执行请求方法;所以 axios 既是函数又是对象

来个例子:

// 声明axios函数
function axios(config) {
	console.log("配置项:", config)
}
// 为axios挂载方法create
axios.create = () => {
	console.log("axios.create方法")
}
// 为axios挂载属性get
axios.get = "get"

axios({ method: "post" })
axios.create()
console.log("axios的属性:", axios.get)

手写axios源码系列一:axios核心知识点

我们还可以打印一下 axios :

console.dir(axios)

手写axios源码系列一:axios核心知识点
可以看到 axios 是一个函数,且身上挂载有 create 方法以及 get 属性。

去看过 axios 的源码就知道,axios 本质上是一个函数,只是将 Axios 类的原型对象方法以及实例对象方法复制到了 axios 函数上面;还有一些其他的属性与方法也挂载到了 axios 函数对象上,如 CancelToken 类、Axios 类等。

2、dispatchRequest 发送请求

在axios中有两种请求方式,根据不同的平台(platform)来使用不同的请求方式:

  1. xhr(XMLHttpRequest),也就是常说的AJAX。(浏览器)
  2. http(Nodejs)

我们只来探究一下浏览器端的就好。

使用 axios 发送 http 请求时,其实底层调用的只有一个方法,就是 Axios.prototype.request 方法。Axios.prototype.request 方法又执行 dispatchRequest 方法,在 dispatchRequest 方法中使用 adapters.getAdapter 方法来区分是使用 xhr 还是 http 发送请求。

流程图:
手写axios源码系列一:axios核心知识点

dispatchRequest 模块是真正发送请求的地方:

function dispatchRequest(config) {
  // 根据适配器获取发送请求的方式时xhr还是http
  const adapter = adapters.getAdapter(config.adapter || defaults.adapter);
  // 返回promise对象
  return adapter(config).then(
    response => {
      return response
    },
    err => {
      throw new Error(err)
    })
}

3、interceptors 拦截器

在项目中,一般发送 http 请求时会对请求和响应进行一些特殊处理:判断 token,设置请求头,统一处理响应错误信息等。如果要挨个对每个请求都做处理的话太麻烦,方便起见,axios 提供了拦截器。

拦截器分为:

  • 请求拦截器 axios.interceptors.request
  • 响应拦截器 axios.interceptors.response

请求拦截器的使用:

axios.interceptors.request.use(function (config) {
	// 设置token
	const token = sessionStorage.getItem("token");
	if (token) { config.headers.token = token };
	//返回config配置项
	return config;
}, function (error) {
	return Promise.reject(error);
})

响应拦截器的使用:

axios.interceptors.response.use(function (response) {
	// 全局统一设置错误信息提示,code、msg是与后台约定好的返回值
	const { code, msg } = response.data;
	if (code === 0){ 
		return response.data;
	} else {
		Notify({ type: 'danger', msg, duration: 5000 });
		return Promise.reject(new Error(msg || 'Error'));
	}
}, function (error) {
	const { message} = error.response.data;
	Notify({ type: 'danger', message, duration: 5000 });
	return Promise.reject(error);
})

拦截器可以设置多个,例如:

// 请求拦截器1
axios.interceptors.request.use(function one(config){
	console.log("请求拦截器 1");
	return config;
},function one(error){
	return Promise.reject(error);
})
// 请求拦截器2
axios.interceptors.request.use(function two(config){
	console.log("请求拦截器 2");
	return config;
},function two(error){
	return Promise.reject(error);
})
// 响应拦截器1
axios.interceptors.response.use(function one(response){
	console.log("响应拦截器 1");
	return response;
},function one(error){
	return Promise.reject(error);
})
// 响应拦截器2
axios.interceptors.response.use(function two(response){
	console.log("响应拦截器 2");
	return response;
},function two(error){
	return Promise.reject(error);
})

当我发送一个请求时,会按照以下顺序打印出结果:

请求拦截器 2
请求拦截器 1
响应拦截器 1
响应拦截器 2
response

为什么会先打印请求拦截器 2,然后再打印请求拦截器 1 呢?

这里就涉及到源码中拦截器的执行了。

源码 Axios.prototype.request 方法中定义了一条执行链 chain = [dispatchRequest, undefined]。然后获取请求拦截器,使用array.unshift() 将其添加到执行链 chain 的头部;获取响应拦截器,使用 array.push() 将其添加到执行链的尾部,就形成了最终的执行顺序:

chain = [
	two(config),
	two(error),
	one(config),
	one(error),
	dispatchRequest,  // 发送请求
	undefined,
	one(response),
	one(error),
	two(response),
	two(error),
]

4、cancelToken 取消请求

请求既可以发送,也可以进行取消,取消请求使用的是 xhr.abort() 方法,abort 就是中止的意思。

取消请求 | Axios 中文文档 | Axios 中文网

取消请求的方式有两种:

  1. 使用 CancelToken(官方在 axios 版本0.22.0 开始被弃用,但还是做了兼容处理,仍可使用)

    const CancelToken = axios.CancelToken;
    let source = CancelToken.source();
    axios.get(url, {
    	cancelToken: source.token
    }).then(response => {
    	// ...
    })
    // 取消请求
    source.cancel();
    
  2. 使用 AbortController(官方推荐的使用方式,而且非常简单)

    const controller = new AbortController();
    axios.get(url, {
    	signal: controller.signal
    }).then(response => {
    	// ...
    })
    // 取消请求
    controller.abort();
    

    AbortController 接口表示一个控制器对象,允许你根据需要中止一个或多个 Web 请求

    下图为 AbortController 类:

    手写axios源码系列一:axios核心知识点
    可以看出,abort 为 AbortController 类的原型对象的方法,signal 是 AbortSignal 类生成的实例对象。

在 axios 源码中,取消请求封装了一个 CancelToken 类,使用发布/订阅模式进行取消请求的统一集中处理。在AJAX发送请求时,对取消请求 onCanceled 方法进行了订阅,在 CancelToken 内部使用 promise 对象向外暴露了 resolve 方法,在执行 source.cancel() 取消请求时,其实是执行了内部暴露的 resolve 方法,resolve 执行,则 promise 的状态由 pending 变为 fulfilled,然后 promise.then() 方法执行,而订阅的 onCanceled 方法就是放在 promise.then() 中去执行的。

// xhr.js
const xhr = new XMLHttpRequest();
onCanceled = () => {
	xhr.abort();
}
config.cancelToken.subscribe(onCanceled)
// CancelToken.js
class CancelToken {
	constructor(executor){
		let resolvePromise;
		this._listeners = [];
		this.promise = new Promise(resolve => {
			resolvePromise = resolve;  // 向外暴露resolve方法
		})
		// executor执行器函数执行,传入参数为一个函数
		executor(function c(){
			resolvePromise();  // 执行resolve方法
		})
		this.promise.then(()=>{
			let len = this._listeners.length;
			while(len-- > 0){
				this._listeners[i](); // 执行onCanceled()
			}
		})
	}
	subscribe(fn){
		this._listeners.push(fn);  //收集依赖
	}
}

不理解不要紧,因为取消请求逻辑在我看来是 axios 源码里面最绕人,最难理解的知识点,因为这里使用到了设计模式、闭包、promise异步编程、高阶函数等知识点,你只要有其中一个知识点模糊,估计就有点麻烦了,只能多学多看。

放张图理解一下:
手写axios源码系列一:axios核心知识点文章来源地址https://www.toymoban.com/news/detail-420992.html

到了这里,关于手写axios源码系列一:axios核心知识点的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Vue入门——核心知识点

    Vue是一套用于 构建用户界面 的 渐进式 JS框架。 构建用户界面:就是将后端返回来的数据以不同的形式(例如:列表、按钮等)显示在界面上。 渐进式:就是可以按需加载各种库。简单的应用只需要一个核心库即可,复杂的应用可以按照需求引入各种Vue插件。 采用组件化模式

    2024年02月06日
    浏览(52)
  • 一文吃透Tomcat核心知识点

    首先,看一下整个架构图。最全面的Java面试网站 接下来简单解释一下。 Server :服务器。Tomcat 就是一个 Server 服务器。 Service :在服务器中可以有多个 Service,只不过在我们常用的这套 Catalina 容器的Tomcat 中只包含一个 Service,在 Service 中包含连接器和容器。一个完整的 Serv

    2024年02月02日
    浏览(46)
  • JavaSE核心基础-循环-知识点

    1.循环概念 循环是在满足条件的情况下,反复的做同一件事。 Java语言中的循环语句有三种,分别是for语句、while语句和do-while语句。程序中需要循环处理时,程序员要根据实际问题,选择适当的循环语句。解决循环问题时一定要找到循环条件和循环操作。 2.for循环语句格式

    2024年02月22日
    浏览(40)
  • redis核心知识点简略笔记

    value数据类型 string 二进制安全 list 有序、可重复 set 无序、不重复 hash field-value的map sorted set 不重复、通过double类型score分数排序 场景 string 计数器 缓存 分布式锁 访问频率控制 分布式session hash 购物车等对象属性灵活修改 list 定时排行榜 set 收藏 sorted set 实时排行榜 持久化

    2024年02月13日
    浏览(50)
  • 垃圾回收的核心知识点解析

    Java运行时内存中的程序计数器、虚拟机栈、本地方法栈这三部分区域其生命周期与相关线程有关,随线程而生,随线程而灭。而程序计数器就是一个单纯存地址的整数也不需要关心,因此我们GC(垃圾回收)的主要目标就是堆(堆中存放着几乎所有实例对象)! 一个对象,如

    2024年02月16日
    浏览(38)
  • Java核心技术知识点笔记—并发

    前言:多任务(multitasking),即同一刻运行多个程序的能力。并发执行的进程数目并不是由CPU数目制约的。操作系统将CPU的时间片分配给每一个进程,给人并行处理的感觉。 1、线程(thread):多线程程序的概念,即可以同时执行多个任务的程序。其中,每个任务称为一个线

    2023年04月12日
    浏览(77)
  • Java核心知识点整理大全23-笔记

    目录 21. JAVA 算法 21.1.1. 二分查找 21.1.2.冒泡排序算法 21.1.3. 插入排序算法 21.1.4. 快速排序算法 21.1.1. 希尔排序算法 21.1.2. 归并排序算法 21.1.3. 桶排序算法 21.1.4. 基数排序算法 21.1.5. 剪枝算法 21.1.6. 回溯算法 21.1.7. 最短路径算法 21.1.8. 最大子数组算法 21.1.9. 最长公共子序算法

    2024年02月04日
    浏览(48)
  • 【大数据】Hudi 核心知识点详解(二)

    😊 如果您觉得这篇文章有用 ✔️ 的话,请给博主一个一键三连 🚀🚀🚀 吧 (点赞 🧡、关注 💛、收藏 💚)!!!您的支持 💖💖💖 将激励 🔥 博主输出更多优质内容!!! Hudi 核心知识点详解(一) Hudi 核心知识点详解(二) Hudi 提供了 Hudi 表的概念,这些表支持

    2024年02月03日
    浏览(38)
  • 关于“Python”的核心知识点整理大全63

    目录 20.2.11 使用 Git 跟踪项目文件 1. 安装Git 2. 配置Git 3. 忽略文件 .gitignore 注意 4. 提交项目 20.2.12 推送到 Heroku 注意 20.2.13 在 Heroku 上建立数据库 20.2.14 改进 Heroku 部署 1. 在Heroku上创建超级用户 注意 注意 如果你阅读完了第17章,就知道Git是一个版本控制程序,让你能够在每次

    2024年01月25日
    浏览(30)
  • 关于“Python”的核心知识点整理大全11

    目录 ​编辑 6.2.4 修改字典中的值  6.2.5 删除键—值对 注意 删除的键—值对永远消失了。  6.2.6 由类似对象组成的字典 6.3 遍历字典 6.3.1 遍历所有的键—值对 6.3.2 遍历字典中的所有键 往期快速传送门👆(在文章最后): 6.2.4 修改字典中的值 要修改字典中的值,可依次指定

    2024年02月05日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包