axios源码中的10多个工具函数,值得一学~
大家好,我是若川。最近组织了源码共读活动,感兴趣的可以点此加我微信 ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。
本文来自读者Ethan01
投稿,写了axios
源码中的工具函数~非常值得一学。原文链接:https://juejin.cn/post/7042610679815241758
1.前言
歌德说过:读一本好书,就是在和高尚的人谈话。
同理,读优秀的开源项目的源码,就是在和牛逼的大佬交流。
之前总觉得阅读源码是一件了不起的事情,是只有大佬才会去做的事。其实源码也不是想象的那么难,至少有很多看得懂。 比如源码中的工具函数,就算是初级的前端开发也是能够看懂的。重要的是,要迈出这一步,阅读源码没什么的。
阅读本文,你将学到:
1、javascript、nodejs调试技巧及调试工具;
2、如何学习调试axios源码;
3、如何学习优秀开源项目的代码,应用到自己的项目;
4、axios源码中实用的工具函数;
2.环境准备
2.1 读开源项目的贡献指南
打开 axios[1] , 你会惊奇的发现,这不是在浏览器中打开了一个vscode
吗?你没有看错,确实是在浏览器中打开了vscode
,而且还打开了axios
的源码。如果你仔细看了浏览器地址栏里的url
, 你会发现github
后多了1s
,顾名思义,就是1s
打开github
上的项目。一个小扩展:在每一个github
项目中的url
里直接加上1s
,就能在网页版vscode
中查看源码了(不过貌似现在只能查看,不能调试,调试的话还是要把源码clone
到本地)。
开源项目一般能在根目录下的README.md
文件或CONTRIBUTING.md
中找到贡献指南。贡献指南中说明了参与贡献代码的一些注意事项,比如:代码风格、代码提交注释格式、开发、调试等。
打开CONTRIBUTING.md[2],可以看到在54
行的内容:
Running sandbox in browser```bash
$ npm start
# Open 127.0.0.1:3000
这里就是告诉我们在如何在浏览器中运行项目的。
2.2 克隆项目并运行
这里使用axios
的版本是v0.24.0
;
git clone https://github.com/axios/axios.gitcd axiosnpm start打开 http://localhost:3000/
这时候可以看到这么一个页面:
打开浏览器的控制台,选中source
选项,然后在axios
目录中可以找到源码,如下图:
这个axios.js
就是入口文件,这时候就可以随意打断点进行调试了。
其实,阅读所有源码的流程都类似,之所以说的这么详细,是为了能够让没有阅读过源码的同学也能够跟着一步一步的阅读起来。当你读完之后,肯定会有不少的收获,把这个过程和收获记录下来,慢慢的提升自己,早晚会成为大佬。
3. 工具函数
今天的主角是`utils.js`[3]文件, 以下列出了文件中的工具函数:
3.1 isArray
判断数组
var toString = Object.prototype.toString;// 可以通过 `toString()` 来获取每个对象的类型
// 一般返回值是 Boolean 类型的函数,命名都以 is 开头
function isArray(val) {return toString.call(val) === '[object Array]';
}
3.2 isUndefined
判断Undefined
// 直接用`typeof`判断
// 注意 typeof null === 'object'
function isUndefined(val) {return typeof val === 'undefined';
}
3.3 isBuffer
判断 buffer
// 先判断不是 `undefined`和`null`
// 再判断 `val`存在构造函数,因为`Buffer`本身是一个类
// 最后通过自身的`isBuffer`方法判断function isBuffer(val) {return val !== null && !isUndefined(val) && val.constructor !== null && !isUndefined(val.constructor)&& typeof val.constructor.isBuffer === 'function' && val.constructor.isBuffer(val);
}
什么是Buffer?
JavaScript 语言自身只有字符串数据类型,没有二进制数据类型。
但在处理像TCP流或文件流时,必须使用到二进制数据。因此在 Node.js
中,定义了一个Buffer
类,该类用来创建一个专门存放二进制数据的缓存区。详细可以看 官方文档[4] 或 更通俗易懂的解释[5]。
因为axios
可以运行在浏览器和node
环境中,所以内部会用到nodejs
相关的知识。
3.4 isFormData
判断FormData
// `instanceof` 运算符用于检测构造函数的 `prototype` 属性是否出现在某个实例对象的原型链上function isFormData(val) {return (typeof FormData !== 'undefined') && (val instanceof FormData);
}// instanceof 用法function C() {}
function D() {}const c = new C()c instanceof C // output: true 因为 Object.getPrototypeOf(c) === C.prototypec instanceof Object // output: true 因为 Object.prototype.isPrototypeOf(c)c instanceof D // output: false 因为 D.prototype 不在 c 的原型链上
3.5 isObject
判断对象
// 排除 `null`的情况
function isObject(val) {return val !== null && typeof val === 'object';
}
3.6 isPlainObject
判断 纯对象
纯对象:用{}
或new Object()
创建的对象。
function isPlainObject(val) {if (Object.prototype.toString.call(val) !== '[object Object]') {return false;}var prototype = Object.getPrototypeOf(val);return prototype === null || prototype === Object.prototype;
}// 例子1
const o = {name: 'jay}
isPlainObject(o) // true// 例子2
const o = new Object()
o.name = 'jay'
isPlainObject(o) // true// 例子3
function C() {}
const c = new C()
isPlainObject(c); // false// 其实就是判断目标对象的原型是不是`null` 或 `Object.prototype`
3.7 isDate
判断Date
function isDate(val) {return Object.prototype.toString.call(val) === '[object Date]';
}
3.8 isFile
判断文件类型
function isFile(val) {return Object.prototype.toString.call(val) === '[object File]';
}
3.9 isBlob
判断Blob
function isBlob(val) {return Object.prototype.toString.call(val) === '[object Blob]';
}
Blob
对象表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取。
3.10 isFunction
判断函数
function isFunction(val) {return Object.prototype.toString.call(val) === '[object Function]';
}
3.11 isStream
判断是否是流
// 这里`isObject`、`isFunction`为上文提到的方法
function isStream(val) {return isObject(val) && isFunction(val.pipe);
}
3.12 isURLSearchParams
判断URLSearchParams
function isURLSearchParams(val) {return typeof URLSearchParams !== 'undefined' && val instanceof URLSearchParams;
}// 例子
const paramsString = "q=URLUtils.searchParams&topic=api"
const searchParams = new URLSearchParams(paramsString);
isURLSearchParams(searchParams) // true
URLSearchParams
接口定义了一些实用的方法来处理 URL 的查询字符串,详情可看 MDN[6]:
var paramsString = "q=URLUtils.searchParams&topic=api"
var searchParams = new URLSearchParams(paramsString);for (let p of searchParams) {console.log(p);
}// 输出
[ 'q', 'URLUtils.searchParams' ]
[ 'topic', 'api' ]searchParams.has("topic") === true; // true
searchParams.get("topic") === "api"; // true
searchParams.getAll("topic"); // ["api"]
searchParams.get("foo") === null; // true
searchParams.append("topic", "webdev");
searchParams.toString(); // "q=URLUtils.searchParams&topic=api&topic=webdev"
searchParams.set("topic", "More webdev");
searchParams.toString(); // "q=URLUtils.searchParams&topic=More+webdev"
searchParams.delete("topic");
searchParams.toString(); // "q=URLUtils.searchParams"
3.13 trim
去除首尾空格
// `trim`方法不存在的话,用正则
function trim(str) {return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, '');
}
3.14 isStandardBrowserEnv
判断标准浏览器环境
function isStandardBrowserEnv() {if (typeof navigator !== 'undefined' && (navigator.product === 'ReactNative' ||navigator.product === 'NativeScript' ||navigator.product === 'NS')) {return false;}return (typeof window !== 'undefined' &&typeof document !== 'undefined');
}
但是官方已经不推荐使用这个属性navigator.product
。
3.15 forEach
遍历对象或数组
保留了英文注释,提升大家的英文阅读能力。
/*** Iterate over an Array or an Object invoking a function for each item.* 用一个函数去迭代数组或对象** If `obj` is an Array callback will be called passing* the value, index, and complete array for each item.* 如果是数组,回调将会调用value, index, 和整个数组** If 'obj' is an Object callback will be called passing* the value, key, and complete object for each property.* 如果是对象,回调将会调用value, key, 和整个对象** @param {Object|Array} obj The object to iterate* @param {Function} fn The callback to invoke for each item*/function forEach(obj, fn) {// Don't bother if no value provided// 如果值不存在,无需处理if (obj === null || typeof obj === 'undefined') {return;}// Force an array if not already something iterable// 如果不是对象类型,强制转成数组类型if (typeof obj !== 'object') {obj = [obj];}if (isArray(obj)) {// Iterate over array values// 是数组,for循环执行回调fnfor (var i = 0, l = obj.length; i < l; i++) {fn.call(null, obj[i], i, obj);}} else {// Iterate over object keys// 是对象,for循环执行回调fnfor (var key in obj) {// 只遍历可枚举属性if (Object.prototype.hasOwnProperty.call(obj, key)) {fn.call(null, obj[key], key, obj);}}}
}
所以,源码为什么不用forEach
和for...in...
呢???????
3.16 stripBOM
删除UTF-8
编码中BOM
/*** Remove byte order marker. This catches EF BB BF (the UTF-8 BOM)** @param {string} content with BOM* @return {string} content value without BOM*/function stripBOM(content) {if (content.charCodeAt(0) === 0xFEFF) {content = content.slice(1);}return content;
}
所谓 BOM
,全称是Byte Order Mark
,它是一个Unicode
字符,通常出现在文本的开头,用来标识字节序。UTF-8
主要的优点是可以兼容ASCII
,但如果使用BOM
的话,这个好处就荡然无存了。
4.总结
本文主要介绍了axios
源码的调试过程,以及介绍了一些utils.js
中的非常实用的工具函数;相信通过阅读源码,日积月累,并把这些代码或思想应用的自己项目中去,相信能够很好的提升自己的编码能力。
come on! worker!
同时也推荐一些好用的工具:
浏览器中运行`vscode`, 查看源码[7]
代码沙盒,能运行多种语言,且可以添加依赖[8]
vs code 的 code Runner插件[9]
参考资料
[1]
axios: https://github1s.com/axios/axios
[2]
CONTRIBUTING.md: https://github1s.com/axios/axios/blob/HEAD/CONTRIBUTING.md
[3]
utils.js
: https://github.com/axios/axios/blob/master/lib/utils.js
[4]
官方文档: http://nodejs.cn/api/buffer.html#buffer
[5]
更通俗易懂的解释: https://www.runoob.com/nodejs/nodejs-buffer.html
[6]
MDN: https://developer.mozilla.org/zh-CN/docs/Web/API/URLSearchParams
[7]
浏览器中运行vscode
, 查看源码: https://github1s.com/axios/axios
[8]
代码沙盒,能运行多种语言,且可以添加依赖: https://codesandbox.io/
[9]
vs code 的 code Runner插件: https://marketplace.visualstudio.com/items?itemName=formulahendry.code-runner
················· 若川简介 ·················
你好,我是若川,毕业于江西高校。现在是一名前端开发“工程师”。写有《学习源码整体架构系列》20余篇,在知乎、掘金收获超百万阅读。
从2014年起,每年都会写一篇年度总结,已经写了7篇,点击查看年度总结。
同时,最近组织了源码共读活动,帮助3000+前端人学会看源码。公众号愿景:帮助5年内前端人走向前列。
识别上方二维码加我微信、拉你进源码共读群
今日话题
略。分享、收藏、点赞、在看我的文章就是对我最大的支持~
axios源码中的10多个工具函数,值得一学~相关推荐
- 初学者也能看懂的 Vue2 源码中那些实用的基础工具函数
1. 前言 大家好,我是若川.最近组织了源码共读活动,感兴趣的可以加我微信 ruochuan12 想学源码,极力推荐之前我写的<学习源码整体架构系列>jQuery.underscore.l ...
- 初学者也能看懂的 Vue3 源码中那些实用的基础工具函数
1. 前言 大家好,我是若川.最近组织了源码共读活动.每周读 200 行左右的源码.很多第一次读源码的小伙伴都感觉很有收获,感兴趣可以加我微信ruochuan12,拉你进群学习. 写相对很难的源码,耗 ...
- 阅读axios源码中工具函数
首先下载axios的源码, 然后运行start命令, 就会打开一个网址, 这网址就是axios的调试网址 在lib文件夹下有一个utils.js文件,这个就是工具函数的文件. 一,判断类型的方法有三种 ...
- 学习尤雨溪写的 Vue3 源码中的简单工具函数
大家好,我是若川.最近组织了源码共读活动.每周读 200 行左右的源码.很多第一次读源码的小伙伴都感觉很有收获,感兴趣可以加我微信ruochuan12,拉你进群学习. 初学者也能看懂的 Vue3 源码 ...
- axios源码——工具函数utils.js
文章目录 前言 一.工具函数所在目录 二.判定数据类型的函数 1.isArray(判定数组) 2.isString(判定字符串) 3.isNumber(判定数值) 4.isObject(判定对象) 5 ...
- 学习 axios 源码整体架构,打造属于自己的请求库
前言 这是学习源码整体架构系列第六篇.整体架构这词语好像有点大,姑且就算是源码整体结构吧,主要就是学习是代码整体结构,不深究其他不是主线的具体函数的实现.本篇文章学习的是实际仓库的代码. 学习源码整体 ...
- 总结|ORB_SLAM2源码中字典使用细节
点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 前言 前段时间,主要对ORB-SLAM2中字典的训练与使用进行了些研究,关于字典的训练之前也写过一篇文 ...
- axios post object object_深入学习Axios源码(构建配置)
axios是我们日常代码中常用的一个http库,它可以用来在浏览器或者node.js中发起http请求:它强大的功能和简单易用的API受到了广大前端童鞋们的青睐:那么它内部是如何来实现的呢,让我们走进 ...
- android底层截图,Android源码中屏幕截图的实现
Android手机一般都自带有手机屏幕截图的功能:在手机任何界面(当然手机要是开机点亮状态),通过按组合键,屏幕闪一下,然后咔嚓一声,截图的照片会保存到当前手机的图库中,真是一个不错的功能! 以我手头 ...
最新文章
- 从AI应用的五大要素看,AI产业存在哪些机会?(算力算法)
- (0071)iOS开发之Category VS Extension区别理解
- C++之string类
- 把二叉搜索树转换为累加树—leetcode538
- 在类模板的声明和定义中把.h与.cpp分离
- oracle中角色和用户权限,Oracle用户、角色、权限管理
- c语言某一行不被优化,C语言优化小技巧
- 没有光驱怎样从硬盘上安装Windows XP系统
- 华为Mate 20 X 5G版打通5G电话:音质饱满画面清晰
- flask 允许内网访问
- jquery 动态添加,降低input表单的方法
- Atitit 圣爱提拉克斯工作最紧张的时候 11月,圣爱提拉克斯进入了一年中工作最紧张的时候。 过去,他每个月都要撰写不少文章、与不同的人愉快地交谈,教育他们沿着圣爱提拉克斯创造的世界上最伟大的圣
- Couchbase使用入门
- web前端——qq登录界面
- 软回车和硬回车 MS高级office
- 高等概率论 Chapter 5. Random Variables on a Countable Space
- 实时音视频开发理论必备:如何省流量?视频高度压缩背后的预测技术
- 登录网页无法连接服务器,"无法连接到服务器,用户xxx登陆失败" 解决办法
- React之官网首页篇
- 林仕鼎:架构师成长之路----如何突破瓶颈