近期阿宝哥在团队内搞了一个 「如何读源码」 的专题,主要目的是让团队的小伙伴们了解读源码的思路与技巧。在此期间,阿宝哥也写了 77.9K 的 Axios 项目有哪些值得借鉴的地方、从 12.9K 的前端开源项目我学到了啥 和 如何让你的 Express 飞起来 三篇源码解析的文章。
其中前两篇在「掘金社区」获得不错的评价,平均 630 多个?,所以阿宝哥就想写一篇文章来分享一下本人读源码的思路、技巧与工具。
好的,让我们开始出发吧!在进入正题之前,我们先来个读源码前的 「灵魂四连问」 热热身。
一、灵魂四连问
1.1 为什么要读源代码
1.2 如何选择项目
1.3 如何阅读源码
1.4 有实际的案例么
既然前两篇文章比较受大家喜欢,接下来阿宝哥就以最受欢迎的 Axios 为例,来分享一下读源码的思路与技巧。
二、如何品读 Axios?
2.1 走进 Axios
Axios 是一个基于 Promise 的 HTTP 客户端,同时支持浏览器和 Node.js 环境。它是一个优秀的 HTTP 客户端,被广泛地应用在大量的 Web 项目中。
由上图可知,Axios 项目的 Star 数为 「78.1K」,Fork 数也高达 「7.3K」,是一个很优秀的开源项目,所以值得大家细细品读。
2.2 发现 Axios 的美
在确认 Axios 为 “追求目标” 之后,下一步我们就需要来发现它身上的优点(特性):
每个人对 “美” 都有不同的看法,对于阿宝哥来说,我看中了图中已选中的三点。因此,它们也很光荣地成为读源码的三个切入点。当然切入点也不是越多越好,可以先找自己最感兴趣的地方作为切入点。需要注意的是,如果切入点之间有关联关系的话,建议做个简单的排序。
2.3 感受 Axios 的美
选择切入点之后,我们就可以开始逐一感受 Axios 的设计之美。以 「能够拦截请求与响应」 这个切入点为例,首先我们就会接触到 「拦截器」 的概念。所以我们需要先了解拦截器是什么、拦截器有什么作用以及如何使用拦截器,这里我们可以从项目的 「官方文档」 或者项目中的 「README.md」 文档入手。
2.3.1 拦截器的作用
Axios 提供了请求拦截器和响应拦截器来分别处理请求和响应,它们的作用如下:
- 请求拦截器:该类拦截器的作用是在请求发送前统一执行某些操作,比如在请求头中添加 token 字段。
- 响应拦截器:该类拦截器的作用是在接收到服务器响应后统一执行某些操作,比如发现响应状态码为 401 时,自动跳转到登录页。
2.3.2 拦截器的使用
代码语言:javascript复制// 添加请求拦截器 —— 处理请求配置对象
axios.interceptors.request.use(function (config) {
config.headers.token = 'added by interceptor';
return config;
});
// 添加响应拦截器 —— 处理响应对象
axios.interceptors.response.use(function (data) {
data.data = data.data ' - modified by interceptor';
return data;
});
axios({
url: '/hello',
method: 'get',
}).then(res =>{
console.log('axios res.data: ', res.data)
});
在了解完拦截器的作用和用法之后,我们就会把焦点聚焦到 「axios」 对象,因为注册拦截器和发送请求都与它有紧密的联系。不过在看具体源码之前,阿宝哥建议先对功能点做一下梳理。以下是阿宝哥的分析思路:
Axios 的作用是用于发送 HTTP 请求,请求拦截器和响应拦截器分别对应于 HTTP 请求的不同阶段,它们的本质是一个实现特定功能的函数。这时我们就可以按照功能把发送 HTTP 请求拆解成不同类型的子任务,比如有 「用于处理请求配置对象的子任务」,「用于发送 HTTP 请求的子任务」 和 「用于处理响应对象的子任务」。当我们按照指定的顺序来执行这些子任务时,就可以完成一次完整的 HTTP 请求。
既然已经提到了任务,我们就会联想到任务管理系统的基本功能:任务注册、任务编排(优先级排序)和任务调度等。因此我们就可以考虑从 「任务注册、任务编排和任务调度」 三个方面来分析 Axios 拦截器的实现。
2.3.3 任务注册
代码语言:javascript复制// 添加请求拦截器 —— 处理请求配置对象
axios.interceptors.request.use(function (config) {
config.headers.token = 'added by interceptor';
return config;
});
// 添加响应拦截器 —— 处理响应对象
axios.interceptors.response.use(function (data) {
data.data = data.data ' - modified by interceptor';
return data;
});
在 lib/axios.js
路径下,我们可以找到 「axios」 对象的定义。为了能直观地了解对象之间的关系,阿宝哥建议大家在读源码的过程中,多动手画画图。比如阿宝哥使用下图来总结一下 Axios
对象与 InterceptorManager
对象的内部结构与关系:
2.3.4 任务编排
现在我们已经知道如何注册拦截器任务,但仅仅注册任务是不够,我们还需要对已注册的任务进行编排,这样才能确保任务的执行顺序。
同样对于任务编排,也可以使用图的形式来展现任务编排后的结果。「这里有一个小技巧,就是可以采用对比的形式来展示任务编排后的结果,这样子会更加清楚任务编排的处理逻辑。」
2.3.5 任务调度
任务编排完成后,要发起 HTTP 请求,我们还需要按编排后的顺序执行任务调度。
❝需要注意的是:在阅读源码过程中,不要太在意细节。比如在研究 Axios 拦截器原理时,不需要再深入了解 「dispatchRequest」 背后的具体实现,只需知道该方法用于实现发送 HTTP 请求即可,这样才不会把整个线路拉得太长。 ❞
在分析完特定的功能点之后,也许你已经读懂的具体的源代码。但阿宝哥觉得这并不是最重要的,「更重要的是思考它的设计思想,这样设计有什么好处,对于我们有没有什么值得借鉴和学习的地方」。比如参考 Axios 拦截器的设计模型,我们就可以抽出以下通用的任务处理模型:
上面阿宝哥以 Axios 的拦截器为例,分享了读 Axios 源码的思路与技巧。接下来阿宝哥来分享一些读源码的建议和辅助工具。
三、读源码的建议
四、读源码辅助工具
如果你对下列辅助工具感兴趣的话,可以通过以下图片来源的链接,来直接打开每个工具的在线地址。
(图片来源:https://www.processon.com/view/link/5f6d2beff346fb166d0ac4fd)
五、总结
其实除了上面的内容之外,读优秀开源项目还有挺多值得关注的地方。阿宝哥在学习 BetterScroll 项目源码时,总结了一张思维导图:
(图片来源:https://www.processon.com/view/link/5f6d2beff346fb166d0ac4fd)
下面阿宝哥用一张图来总结一下 axios 和 better-scroll 这两个开源项目的学习路线:
❝1、Axios 项目的切入点是从 Github 中的功能特性中筛选出来的; 2、BetterScroll 的切入点是从掘金上 “BetterScroll 2.0 发布:精益求精,与你同行” 这篇文章中介绍的功能亮点中找到的。 ❞
除此之外,阿宝哥也来简单总结一下本文介绍的读源码的思路与技巧:
- 站在巨人的肩膀,提前阅读一些项目相关的优质文章;
- 汇总学习或工作中遇到的问题,带着问题进行源码学习;
- 明确阅读源码的主线或切入点;
- 尽可能从简单的示例出发来分析每个功能点;
- 先梳理清楚主要流程,不要太在意细节,避免把整个线路拉得太长;
- 在阅读源码过程中,要多多画图,这样理解起来会更加直观。
本文阿宝哥分享了个人读源码的思路、技巧与工具,希望阅读完本文能对你有所启发或帮助。如果你有读源码更好的思路与技巧,欢迎随时跟阿宝哥交流。有写得不好的地方,也请各位见谅哈。
你可能还想看
2020年中大厂前端面试总结 如何学习React源码 如何学习源码 | 如何高效学习一个新知识 为什么要学习源码,怎么学习?
1.学习 jQuery 源码整体架构,打造属于自己的 js 类库 2.学习 underscore 源码整体架构,打造属于自己的函数式编程类库 3.学习 lodash 源码整体架构,打造属于自己的函数式编程类库 4.学习 sentry 源码整体架构,打造属于自己的前端异常监控SDK 5.学习 vuex 源码整体架构,打造属于自己的状态管理库 6.学习 axios 源码整体架构,打造属于自己的请求库 7.学习 koa 源码的整体架构,浅析koa洋葱模型原理和co原理 8.学习 redux 源码整体架构,深入理解 redux 及其中间件原理
最后
一般人都看不到文章末尾,看到这里你已经超越90%的人了。