当前位置: 首页 > news >正文

梅开二度的 axios 源码阅读,三千字详细分享功能函数,帮助扩展开发思维

前言

第一遍看 axios 源码,更多的是带着日常开发的习惯,时不时产生出点联想。

第二遍再看 axios 源码,目标明确,就是奔着函数来的。

当有了明确清晰的目标,阅读速度上来了,思绪也转的飞快

按图索骥,接下来,将和大家一起,找寻 axios 源码中的功能函数,扩展一下开发思路。

文章速读

阅读文章,可以有以下收获:

功能函数

一般基础的工具函数都会放到 utils.js 文件中。前一篇源码阅读中,介绍了关于类型判断的两种方法。

axios 中有许多模块,不同的模块下包含不同的功能。除了 utils.js 文件,这些模块下的文件也包含函数。我称之为功能函数。

功能函数,按照实际功能需要封装的函数,也许并不是常见功能需要的,但是了解之后,没准能帮助今后用到的时候,快速完成开发。

1.standardBrowserEnv 标准浏览器中对 cookie 的读写删操作

axios 拥有对 cookie 操作的能力,就像叶一一会讲故事一样理所当然。

看源码功能之前,我们先来复习关于 cookie 的知识点。

cookie 的格式

通过 document.cookie 获取 cookie 的值,是一串有特定格式的字符串。它的格式是

cookie1=value; cookie2=value; cookie3=value;

了解了 cookie 的格式,对于它的操作,也自然而然的可以接着看代码了。

cookie 的读写删

在标准浏览器中,对 cookie 的处理被封装在了一个立即执行函数里。

(function standardBrowserEnv() {return {/** * cookie 写入(创建)单个写入 * @param {string} name cookie 名 * @param {string} value cookie 值 * @param {*} expires 过期时间 * @param {*} path cookie所在的目录 * @param {*} domain cookie所在的域 * @param {*} secure 是否可以通过HTTP协议的URL设置布尔值 值为 true 时,表示创建的 cookie 只能用 HTTPS 协议发送 */ write: function write(name, value, expires, path, domain, secure) {	// 先将所有的数据存入数组const cookie = [];cookie.push(name + '=' + encodeURIComponent(value));// 如果过期时间有值且是数值型,则存入其转为根据格林威治时间 (GMT) 转成的字符串if (utils.isNumber(expires)) {cookie.push('expires=' + new Date(expires).toGMTString());}	// 当目录存在且为字符串,则存入cookieif (utils.isString(path)) {cookie.push('path=' + path);}// 当域存在且为字符串,则存入cookieif (utils.isString(domain)) {cookie.push('domain=' + domain);}// 是否可以通过HTTP协议的URL设置布尔值为 true 时,则存入cookieif (secure === true) {cookie.push('secure');}	// 将数组转为字符串,并通过 document.cookie 属性来创建 cookiedocument.cookie = cookie.join('; ');},/** * cookie 读取 单个读取 * @param {string} name cookie 名 */read: function read(name) {	// 正则匹配得到数组const match = document.cookie.match(new RegExp('(^|;\s*)(' + name + ')=([^;]*)'));	// match 匹配的返回值中第四个元素为需要的值return match ? decodeURIComponent(match[3]) : null;},	/** * cookie 删除 单个删除 * @param {string} name cookie 名 */remove: function remove(name) {// 将过期时间设置为过去的时间,即可删除 cookie, 这里设置成了前一天(86400000为1天的毫秒数)this.write(name, '', Date.now() - 86400000);},};
})(); 

使用

// 写入
cookies.write('foo', 'bar');
// 删除
cookies.remove('foo');
// 读取
cookies.read('username=John Doe') // => John Doe 

功能汇总

日期转换 toGMTString 方法

toGMTString() 方法可根据格林尼治标准时间 (GMT) 把 Date 对象转换为字符串,并返回结果。

介绍这个方法,主要科普一个新旧交替的世界标准时间。

首先这个 GMT 和 UTC 的定义如下:

GMT(Greenwich Mean Time):格林尼治标准时间。格林尼治是英国伦敦南郊原皇家格林尼治天文台所在地,地球本初子午线的标界处,世界计算时间和经度的起点。格林尼治标准时间过去被当成世界标准的时间。

UTC(Coordinated Universal Time):协调世界时。又称世界统一时间、世界标准时间、国际协调时间。协调世界时是以原子时秒长为基础,在时刻上尽量接近于世界时的一种时间计量系统。协调世界时是现在使用的世界标准时间。

所以在W3C下面有一行提示:

不赞成使用此方法。请使用 toUTCString() 取而代之!!

toUTCString 方法

根据协调世界时 (UTC) 把 Date 对象转换为字符串,并返回结果。

正则 match 方法

match() 方法可在字符串内检索指定的值,或找到一个或多个正则表达式的匹配。

返回值

它的返回值是一个存放匹配结果的数组。该数组的内容依赖于 regexp 是否具有全局标志 g。

  • 如果 regexp 没有标志 g,那么 match() 方法就只能在 stringObject 中执行一次匹配。

    • 如果找到匹配结果,它将返回一个数组,存放了与它找到的匹配文本有关的信息。数组的第1个元素存放的是匹配的文本,其余的元素存放与正则表达式的子表达式匹配的文本和input、index、groups三个元素。* 如果没找到匹配结果,返回 null。
  • 如果 regexp 具有标志 g,则 match() 方法将执行全局检索,找到 stringObject 中的所有匹配子字符串。

    • 如果找到匹配结果,它将返回一个数组,数组的第1个元素存放的是匹配的文本,其余元素存放匹配的一个或多个文本。* 如果没找到匹配结果,返回 null。

小结

1.对 cookie 的读写删操作还是挺简单的,主要是参数要考虑全面。日常开发中使用频率不是很高,但是如果需求涉及到可以帮助快速完成开发。
2.在 standardBrowserEnv 函数中,不难在里面发现 utils 的身影,所以基础工具函数的建设必不可少。
3.把 Date 对象转换为字符串推荐使用 toUTCString 方法。
4.无法删除的属性,可以设置成无效的值,比如这里的通过过期时间提前于当前时间。再比如前一篇介绍过将属性值设置为 undefined。

2.formDataToJSON 抽丝剥茧 formData 与 Object 的转换

FormData 对象

FormData 对象用以将数据编译成键值对,以便用XMLHttpRequest来发送数据。

FormData 对象主要用于发送表单数据,但亦可用于发送带键数据 (keyed data),而独立于表单使用。一般文件流数据的发送,会用到 FormData 对象。

第一条丝线— parsePropPath

matchAll

matchAll 函数会根据入参的正则表达式和字符串,返回所有匹配项的数组。

/*** It takes a regular expression and a string, and returns an array of all the matches** @param {string} regExp - The regular expression to match against.* @param {string} str - The string to search.** @returns {Array<boolean>}*/
const matchAll = (regExp, str) => {let matches;const arr = [];// matches 为每次匹配正确的值while ((matches = regExp.exec(str)) !== null) {arr.push(matches);}return arr;
} 

regExp.exec 方法

在一个指定字符串中执行一个搜索匹配。返回一个结果数组或 null。

匹配的标准用法就是如上功能中的那样,如果需要进一步了解可以阅读 MDN 文档。

parsePropPath

parsePropPath ****函数会将字符串中的字母匹配出来放到数组中。

但看描述和函数还不太确定具体用法,但是经典的来了。

当我们设计的某个函数不好用文字做描述,可以用举例的方式辅助描述。比如下面这个函数,不但举例,还举了多个例子,所以这个函数的用途一目了然。

/*** It takes a string like `foo[x][y][z]` and returns an array like `['foo', 'x', 'y', 'z']** @param {string} name - The name of the property to get.** @returns An array of strings.*/
function parsePropPath(name) {// foo[x][y][z]// foo.x.y.z// foo-x-y-z// foo x y zreturn utils.matchAll(/\w+|[(\w*)]/g, name).map(match => {	// 匹配值为数组,当匹配的第一个元素为空数组时返回空字符串,否则返回第二个元素或第一个元素存在值的那个。return match[0] === '[]' ? '' : match[1] || match[0];});
} 

第二条丝线— arrayToObject

arrayToObject 函数会将数组转换对象。

/*** Convert an array to an object.** @param {Array<any>} arr - The array to convert to an object.** @returns An object with the same keys and values as the array.*/
function arrayToObject(arr) {const obj = {};// 返回数组索引值的数组const keys = Object.keys(arr);let i;const len = keys.length;let key;for (i = 0; i < len; i++) {key = keys[i];obj[key] = arr[key];}return obj;
} 

第三条丝线— forEachEntry

forEachEntry 函数会循环一个可迭代的对象,直到循环结束,把对象的 key 和 value 返回。

/*** For each entry in the object, call the function with the key and value.** @param {Object<any, any>} obj - The object to iterate over.* @param {Function} fn - The function to call for each entry.** @returns {void}*/
const forEachEntry = (obj, fn) => {const generator = obj && obj[Symbol.iterator];const iterator = generator.call(obj);let result;// 循环直到迭代器已将序列迭代完毕while ((result = iterator.next()) && !result.done) {const pair = result.value;fn.call(obj, pair[0], pair[1]);}
}; 

我找了一个可迭代对象测试了一下输出

const data = new Map();data.set('a', 1);
data.set('b', 2);
data.set('c', 3);forEachEntry(data, (name, value) => {let res = name + '-' + value;console.log('name-value:', res);
});// 输出结果
// > name-value: a-1
// > name-value: b-2
// > name-value: c-3 

formDataToJSON

formDataToJSON函数接受 一个 FormData 对象最终返回 JavaScript 对象。

/*** It takes a FormData object and returns a JavaScript object** @param {string} formData The FormData object to convert to JSON.** @returns {Object<string, any> | null} The converted object.*/
function formDataToJSON(formData) {/** * 递归函数 将 FormData 的键值全部插入到给 target 对象 * @param {Array} path FormData 的属性名数组 * @param {string} value FormData 的属性值 * @param {Object} target 最终的目标对象 * @param {number} index FormData 的属性值数组的索引值 * @returns 递归是否中止的布尔值 */function buildPath(path, value, target, index) {let name = path[index++];// isFinite 函数会先将测试值转换为数字,然后再对其进行是否为有限数检测。const isNumericKey = Number.isFinite(+name);const isLast = index >= path.length;name = !name && utils.isArray(target) ? target.length : name;if (isLast) {// 如果检查对象具有该属性,将 value 添加到对应的数组中if (utils.hasOwnProp(target, name)) {target[name] = [target[name], value];} else {target[name] = value;}return !isNumericKey;}if (!target[name] || !utils.isObject(target[name])) {target[name] = [];}const result = buildPath(path, value, target[name], index);if (result && utils.isArray(target[name])) {target[name] = arrayToObject(target[name]);}return !isNumericKey;}// formData 参数是 FormData 类型且 formData.entries 是一个函数if (utils.isFormData(formData) && utils.isFunction(formData.entries)) {const obj = {};utils.forEachEntry(formData, (name, value) => {buildPath(parsePropPath(name), value, obj, 0);});return obj;}return null;
} 

我找 axios 自带的测试实例中的例子打印了一下结果

对象的值是数组

const formData = new FormData();
formData.append('foo', '1');
formData.append('foo', '2');const res = formDataToJSON(formData);
console.log('res', res); // -> { foo: ['1', '2'] } 

对象

const formData = new FormData();formData.append('foo', '1');
formData.append('bar', '2');const res = formDataToJSON(formData);
console.log('res', res); // -> {foo: '1', bar: '2'} 

嵌套对象

const formData = new FormData();formData.append('foo[bar][baz]', '123');const res = formDataToJSON(formData);
console.log('res', res); // -> { foo : { bar : {baz: '123'} } } 

小结

1.formDataToJSON 函数接受 一个 FormData 对象最终返回 JavaScript 对象。
2.FormData() 构造函数用于创建一个新的FormData对象。该函数在 Web 中可用,一些环境会报错“FormData is not define”。
3.FormData 对象转换 JavaScript 对象的功能不是很常用。但是这里的主要收获是,当函数设计的相对复杂的时候,可以用抽丝剥茧的方式,现将支线整理出来,最终拼凑成一个完整的主线。

总结

功能函数会依据实际需求去实现功能。通过分析 axios 源码中的两个重点的功能函数,学习复杂功能如何设计,以及补充了些知识点,还得到目前代码中有些判断条件简化的收获。

很愉快的一次源码阅读体验。

axios 源码阅读历程

捎带分享一下我关于 axios 源码阅读中的历程。

数月前

因为工作中需要弄清楚 axios 的 request 中的入参而在源码中寻找答案,当时想抽时间进行一次源码阅读,但是没有坚持下去,就此作罢。

数日前

前几天做功能联想,重新开始阅读,这次收获颇多。

最后

最近找到一个VUE的文档,它将VUE的各个知识点进行了总结,整理成了《Vue 开发必须知道的36个技巧》。内容比较详实,对各个知识点的讲解也十分到位。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

相关文章:

梅开二度的 axios 源码阅读,三千字详细分享功能函数,帮助扩展开发思维

前言 第一遍看 axios 源码&#xff0c;更多的是带着日常开发的习惯&#xff0c;时不时产生出点联想。 第二遍再看 axios 源码&#xff0c;目标明确&#xff0c;就是奔着函数来的。 当有了明确清晰的目标&#xff0c;阅读速度上来了&#xff0c;思绪也转的飞快。 按图索骥&a…...

vcs仿真教程

VCS是在linux下面用来进行仿真看波形的工具&#xff0c;类似于windows下面的modelsim以及questasim等工具&#xff0c;以及quartus、vivado仿真的操作。 1.vcs的基本指令 vcs的常见指令后缀 sim常见指令 2.使用vcs的实例 采用的是全加器的官方教程&#xff0c;首先介绍不使用…...

java 自定义json解析注解 复杂json解析 工具类

java 自定义json解析注解 复杂json解析 工具类 目录java 自定义json解析注解 复杂json解析 工具类1.背景2、需求-各式各样的json一、一星难度json【json对象中不分层】二、二星难度json【json对象中出现层级】三、三星难度json【json对象中存在数组】四、四星难度json【json对象…...

类的 6 个默认成员函数

文章目录一、构造函数1. 构造函数的定义2. 编译器生成的构造函数3. 默认构造函数4. 初始化列表5. 内置成员变量指定缺省值(C11)二、析构函数1. 析构函数的定义2. 编译器生成的析构函数3. 自己写的析构函数的执行方式三、拷贝构造函数1. C语言值传递和返回值时存在 bug2. 拷贝构…...

基于Verilog HDL的状态机描述方法

⭐本专栏针对FPGA进行入门学习&#xff0c;从数电中常见的逻辑代数讲起&#xff0c;结合Verilog HDL语言学习与仿真&#xff0c;主要对组合逻辑电路与时序逻辑电路进行分析与设计&#xff0c;对状态机FSM进行剖析与建模。 &#x1f525;文章和代码已归档至【Github仓库&#xf…...

6年软件测试经历:成长、迷茫、奋斗

前言 测试工作6年&#xff0c;经历过不同产品、共事过不同专业背景、能力的同事&#xff0c;踩过测试各种坑、遇到过各种bug。测试职场生涯积极努力上进业务和技术能力快速进步过、也有努力付出却一无所得过、有对测试生涯前景充满希望认为一片朝气蓬勃过、也有对中年危机思考不…...

OpenMMLab AI实战营第五次课程

语义分割与MMSegmentation 什么是语义分割 任务&#xff1a; 将图像按照物体的类别分割成不同的区域 等价于&#xff1a; 对每个像素进行分类 应用&#xff1a;无人驾驶汽车 自动驾驶车辆&#xff0c;会将行人&#xff0c;其他车辆&#xff0c;行车道&#xff0c;人行道、交…...

【软考】系统集成项目管理工程师(二十)项目风险管理

一、项目风险管理概述1. 风险概念2. 风险分类3. 风险成本二、项目风险管理子过程1. 规划风险管理2. 识别风险3. 实施定性风险分析4. 实施定量风险分析5. 规划风险应对6. 控制风险三、项目风险管理流程梳理一、项目风险管理概述 1. 风险概念 风险是一种不确定事件或条件,一旦…...

2017-PMLR-Neural Message Passing for Quantum Chemistry

2017-PMLR-Neural Message Passing for Quantum Chemistry Paper: https://arxiv.org/pdf/1704.01212.pdf Code: https://github.com/brain-research/mpnn 量子化学的神经信息传递 这篇文献作者主要是总结了先前神经网络模型的共性&#xff0c;提出了一种消息传递神经网络&am…...

Python:每日一题之全球变暖(DFS连通性判断)

题目描述 你有一张某海域 NxN 像素的照片&#xff0c;"."表示海洋、"#"表示陆地&#xff0c;如下所示&#xff1a; ....... .##.... .##.... ....##. ..####. ...###. ....... 其中"上下左右"四个方向上连在一起的一片陆地组成一座岛屿…...

企业级安全软件装机量可能大增

声明 本文是学习大中型政企机构网络安全建设发展趋势研究报告. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 研究背景 大中型政企机构是网络安全保护的重中之重&#xff0c;也是国内网络安全建设投入最大&#xff0c;应用新技术、新产品最多的机构…...

为什么要用频谱分析仪测量频谱?

频谱分析仪是研究电信号频谱结构的仪器&#xff0c;用于信号失真度、调制度、谱纯度、频率稳定度和交调失真等信号参数的测量&#xff0c;可用以测量放大器和滤波器等电路系统的某些参数&#xff0c;是一种多用途的电子测量仪器。从事通信工程的技术人员&#xff0c;在很多时候…...

Python环境搭建、Idea整合

1、学python先要下载什么&#xff1f; 2、python官网 3、idea配置Python 4、idea新建python 学python先要下载什么&#xff1f; python是一种语言&#xff0c;首先你需要下载python&#xff0c;有了python环境&#xff0c;你才可以在你的电脑上使用python。现在大多使用的是pyt…...

HTTP请求返回304状态码以及研究nginx中的304

文章目录1. 引出问题2. 分析问题3. 解决问题4. 研究nginx中的3044.1 启动服务4.2 ETag说明4.3 响应头Cache-Control1. 引出问题 之前在调试接口时&#xff0c;代码总出现304问题&#xff0c;如下所示&#xff1a; 2. 分析问题 HTTP 304: Not Modified是什么意思&#xff1f; …...

【GD32F427开发板试用】使用Arm-2D显示电池电量

本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动&#xff0c;更多开发板试用活动请关注极术社区网站。作者&#xff1a;boc 【虽迟但到】 由于快递的原因&#xff0c;11月份申请的&#xff0c;12月1日才收到GD32F427开发板。虽然姗姗来迟&#xff0c;但也没有减少…...

TS第二天 Typesrcipt编译

文章目录自动编译tsconfig.json配置选项include 比较重要excludeextendsfilescompilerOptions 比较重要自动编译 手动模式&#xff1a;每次ts文件修改完&#xff0c;手动编译一次 tsc 01.ts监视模式&#xff1a;ts文件修改完&#xff0c;自动监视编译 tsc 01.ts -w编译所有文…...

基于C#制作一个飞机大战小游戏

此文主要基于C#制作一个飞机大战游戏&#xff0c;重温经典的同时亦可学习。 实现流程1、创建项目2、界面绘制3、我方飞机4、敌方飞机5、子弹及碰撞检测实现流程 1、创建项目 打开Visual Studio&#xff0c;右侧选择创建新项目。 搜索框输入winform&#xff0c;选择windows窗体…...

git修改历史提交(commit)信息

我们在开发中使用git经常会遇到想要修改之前commit的提交信息&#xff0c;这里记录下怎么使用git修改之前已经提交的信息。一、修改最近一次commit的信息 首先通过git log查看commit信息。 我这里一共有6次commit记录。 最新的commit信息为“Merge branch ‘master’ of https:…...

代码解析工具cpg

cpg 是一个跨语言代码属性图解析工具&#xff0c;它目前支持C/C (C17), Java (Java 13)并且对Go, LLVM, python, TypeScript也有支持&#xff0c;在这个项目的根目录下: cpg-core为cpg解析模块的核心功能&#xff0c;主要包括将代码解析为图&#xff0c;core模块只包括对C/C/Ja…...

Linux虚拟机部署Java环境-Jdk-Mysql

Linux虚拟机部署 author hf 1.安装 电脑安装x-shell工具&#xff0c;然后使用堡垒机基础控件windows版进行安装扫描&#xff0c;最后点击自动检测&#xff0c;保证能扫描到X-shell工具的安装路径 使用堡垒机登录快照夏选择工具点击Xshell进行连接 查看linux版本 root:~# ca…...

vscode里如何用git

打开vs终端执行如下&#xff1a; 1 初始化 Git 仓库&#xff08;如果尚未初始化&#xff09; git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

在Ubuntu中设置开机自动运行(sudo)指令的指南

在Ubuntu系统中&#xff0c;有时需要在系统启动时自动执行某些命令&#xff0c;特别是需要 sudo权限的指令。为了实现这一功能&#xff0c;可以使用多种方法&#xff0c;包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法&#xff0c;并提供…...

拉力测试cuda pytorch 把 4070显卡拉满

import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试&#xff0c;通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小&#xff0c;增大可提高计算复杂度duration: 测试持续时间&#xff08;秒&…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

关于 WASM:1. WASM 基础原理

一、WASM 简介 1.1 WebAssembly 是什么&#xff1f; WebAssembly&#xff08;WASM&#xff09; 是一种能在现代浏览器中高效运行的二进制指令格式&#xff0c;它不是传统的编程语言&#xff0c;而是一种 低级字节码格式&#xff0c;可由高级语言&#xff08;如 C、C、Rust&am…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论

路径问题的革命性重构&#xff1a;基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中&#xff08;图1&#xff09;&#xff1a; mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...

解读《网络安全法》最新修订,把握网络安全新趋势

《网络安全法》自2017年施行以来&#xff0c;在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂&#xff0c;网络攻击、数据泄露等事件频发&#xff0c;现行法律已难以完全适应新的风险挑战。 2025年3月28日&#xff0c;国家网信办会同相关部门起草了《网络安全…...

HubSpot推出与ChatGPT的深度集成引发兴奋与担忧

上周三&#xff0c;HubSpot宣布已构建与ChatGPT的深度集成&#xff0c;这一消息在HubSpot用户和营销技术观察者中引发了极大的兴奋&#xff0c;但同时也存在一些关于数据安全的担忧。 许多网络声音声称&#xff0c;这对SaaS应用程序和人工智能而言是一场范式转变。 但向任何技…...