一比一还原axios源码(零)—— 概要
从vue2版本开始,vue-resource就不再被vue所维护和支持,官方也推荐使用axios,所以,从我使用axios至今,差不多有四五年了,这四五年的时间只能算是熟练应用,很多内部的实现和原理不清不楚,导致在开发的时候遇到问题,大多数情况都是凭借经验来“猜测”出答案,这就导致内心深处十分的空虚和忐忑,就像是走路的时候脚步虚浮,跌跌撞撞,一点都不平稳。刚好最近的计划是看源码,所以就从axios开始,详细的去解读整个axios的实现,希望这个系列既是笔记也是分享,让大家知道原理,理解场景,懂得实现。ok,下面我们开始进入正文吧。
axios本身的核心其实就是XMLHttpRequest,但是又不仅仅是XMLHttpRequest。简单来说,一个库或者一个框架,一个项目,它的核心内容都包含了两部分:打包构建和核心源码。那么本系列对打包构建部分一带而过,只是提供了可以调试源码的程度,并不会对打包构建说太多,一方面是自认为水平还达不到对构建也通透的程度,另外一方面,希望可以抽丝剥茧,去繁取简,让源码不再是神秘的、不可触及的,让所有程度的前端同学,都可以从这系列中学到、用到、得到。
哈哈,说多了,下面继续说axios吧。刚才说到了一个项目包含两部分:打包构建和核心源码,那么在核心源码里axios还可以继续拆分出:js代码、typescript声明、单元测试、demo例子。我们这个系列,仅实现:轻量的打包、demo例子和js源码三个部分。当然,或许后续有时间的话,还会把typescript和单元测试、打包构建也都聊一下,不过,那或许得等我学会的时候啦。哈哈。
本系列会在每篇文章中,以axios的api入手,对比原生的XMLHttpRequest,会事先聊一下要实现的axiso API是如何使用的,然后根据该部分内容,逐步实现axios源码。
其次,我还会在gitHub上发布实现的源码,每个章节都对应一个分支,可以具体看到代码的逐步迭代过程。针对每一个章节,深入的学习,另外,虽然我实现的代码尽可能的贴近axios的源码,甚至有一些工具方法,都是完美复制的。但是,在大家看完本系列文章后,我还是建议大家去看看真正的源码,自己fork一份,对比阅读学习。
一、axios项目结构及生态简介
1、axios打包
我们先来看下axios完整的目录结构,每一个文件的含义介绍在CATALOG.md中,大家可以去看下,在这里仅抽出一部分核心的内容说下。
首先整个axios项目的打包构建使用了Grunt,通过Grunt配置一些流程操作,比如单元测试,打包等流程,Grunt算是整个项目构建的流程管控工具。其次,单元测试是用的mocha+karma的体系。然后打包,最终生成包结果是使用了webpack。其他的细节不多说,这不是本系列的重点。过~~
2、axios及其生态
我们可以回顾整个axios的Tags,从最初的0.1.0版本到现在的0.25.0,整个项目的流程管理工具、单元测试工具等,都没有变化,只是在逐渐迭代的过程中加入了typescript声明,单元测试等。从功能上来说,最开始的axios其实是angular生态的一个模块,只有简单的请求方法,并没有现在的cancelToken,interceptor等功能,随着时代的变化,逐步分离出来成为独立的ajax库。更为详细更新过程的大家可以去看axios的UPGRADE_GUIDE.md文档。另外要说一下的是axios的生态,有很多可以配合axios使用的工具,详情可以去axios的ECOSYSTEM.md文档查看。
其实上面说的都是屁话,毛用没有~~~
二、ajax及其相关
这小节我们来聊下客户端与服务器通信的方式有哪些,着重介绍下ajax以及XMLHttpRequest,额外的,还会简单介绍下WebSockets、EventSource、fetch等。ajax和XMLHttpRequest是重点,重点来了!!!
1、ajax和XMLHttpRequest
众所周知,ajax的全称是Asynchronous JavaScript and XML,即异步的Javascript和XML,通过使用ajax可以使用js来发送请求,服务器返回的数据再通过前端js代码,来渲染到页面上。ajax本身并不是一项新技术,而是一些技术的集合。那么,在开始了解ajax之前,假如没有ajax,客户端如何与服务器交互呢?
首先,可以通过iframe,其次还有表单提交,超链接等方式。或者,比较传统的可以通过jsp等后端语言技术来实现。但是,客户端与服务器通信的目的我们实现了,但是有一个核心的问题仍旧无法解决,也就是异步。每一次的表单提交,超链接等,都要刷新整个页面,导致我们的交互体验并不是十分友好。所以,ajax的出现,解决了部分数据刷新的问题,使得数据的获取和局部渲染变得更为便捷。
上面说道,ajax并不是一个新的技术,而是几种技术的组合,那么其中最为核心的就是XMLHttpRequest。具体的XMLHttpRequest文档可以参考MDN。这里不再多说。
以下是一个最简单的XMLHttpRequest请求例子,我们通过这个简单的例子,来看看XMLHttpRequest的一些相关api,这是我们后续实现axios的基础,首先,我们在本地创建一个html文件,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body></body>
<script>
const data = { a: 1, b: 2 };
var request = new XMLHttpRequest();
request.open("POST", "http://httpbin.org/post?a=1&b=2");
request.send(data);
</script>
</html>
我想来想去,核心的代码就这些,很简单,其实就三行代码,但是我们却可以来分析下这三行代码。首先我们创建一个XMLHttpRequest对象,然后通过这个对象实例,调用open方法,然后再调用send方法。那么第一个问题就是,如何拼接url的get请求的query参数?我们知道axios是传入的params对象,所以这就是我要实现的源码之一,再然后,data是个对象,但是body的请求体接收的是一个json字符串,所以我们也要转换。到了这里我们简单的了解了XMLHttpRequest的核心基础API。那么下面我们结合rollup打包工具,来生成一个我们写好的ajax请求的例子。
要注意,这个例子只是一个简单的XMLHttpRequest对象的应用,和axios无关又有关。rollup打包的代码就十来行,大家可以在c0分支中的rollup.config.js中查看,有兴趣的可以关注下,没兴趣的可以不用关注,直接把项目npm run build就可以了。
然后我们在dist的目录下,创建个index.html,内容如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script src="./axios.umd.js"></script>
<script>
zakingAxios();
</script>
</body>
</html>
其实就是引入我们打包后的文件,然后调用。然后打开index.html文件,就可以看到打印出来的axios字符串了。哦对了,lib下的axios文件中的代码是这样的:
function axios() {
console.log("axios");
}
export default axios;
OK。那么下面我们就来写一个例子。哦对,我们请求的接口来自于这个地址:https://httpbin.org/。我们先来看下代码:
function axios() {
const xhr = new XMLHttpRequest();
xhr.open("GET", "https://httpbin.org/get");
xhr.send();
}
export default axios;
然后npm run build重新打包下就可以在控制台看到get请求了。但是这只是最简单的get请求,那我们来增加一点需求。我希望可以给get请求传参数,怎么办?
xhr.open("GET", "https://httpbin.org/get?a=1&b=1&c=1");
那,我用get请求是否可以传递数组和对象呢?ok,这是我们这篇文章留下的第一个问题。跳过,我们继续来增加需求,现在get请求传参数可以了,我想用post请求并且传递个对象,咋整?这是我们在开发中最常见的场景了。我们把代码改一下:
function axios() {
const xhr = new XMLHttpRequest();
xhr.open("POST", "https://httpbin.org/post");
xhr.send({ a: 1, b: 2 });
}
export default axios;
跑起来后我们发现一个问题。诶?怎么会这样?
XMLHttpRequest是不接受对象形式的body的,那么我们把它转换成JSON字符串呢?
xhr.send(JSON.stringify({ a: 1, b: 2 }));
我们发现可以了~~那么接下来,我希望可以收到响应的body咋办呢?
function axios() {
const xhr = new XMLHttpRequest();
xhr.open("POST", "https://httpbin.org/post");
xhr.send(JSON.stringify({ a: 1, b: 2 }));
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.response);
console.log(xhr.responseText);
}
};
}
export default axios;
我们可以通过判断XMLHttpRequest实例对象上的readyState和status来判断请求是否结束,然后获取xhr上的response或者responseText。那么,第二个问题,response和responseText有啥区别?问题的答案可以在这里寻找:https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest。关于readyState和status也都可以在这个链接找到,或者说,关于XMLHttpRequest相关的方法和属性都可以在这里查询。
OK,我们完整的发起了一个POST请求,例子就到此为止,深入的内容我们会在后面的章节实现axios的时候再详细介绍。点到为止。
2、EventSource
EventSource可以让服务器主动发送数据到我们的代码中, 当不需要以消息形式将数据从客户端发送到服务器时,这使它们成为绝佳的选择。例如,对于处理社交媒体状态更新,新闻提要或将数据传递到客户端存储机制(如IndexedDB或Web存储)之类的,EventSource无疑是一个有效方案(这段话是抄的)。具体内容可查看MDN。
3、WebSockets
这个东西相信大家也有一定的了解,它可以在用户的浏览器和服务器之间打开交互式通信会话。使用此API,您可以向服务器发送消息并接收事件驱动的响应,而无需通过轮询服务器的方式以获得响应,可参考MDN。
4、ActiveXObject
这个东西有点陌生,而且有点复杂, 它可以操作文件、文件夹,获取相关信息,发起http请求等,它是一个复杂的功能庞大的对象或者说接口,http请求功能只不过是它的一小部分,发起请求可以通过如下的形式,在之前IE兼容的时候,如果没有XMLHttpRequest,也会使用到ActiveXObject:
new window.ActiveXObject("Mscrosoft.XMLHttp")
这个也简单提一下,过~~,有兴趣自行百度!
4、Fetch
这个东西想必大家都比较熟悉,或多或少听说过,算是XMLHttpRequest的升级版,也是用来在浏览器中发起http请求。fetch是用了promise,简洁了用法。并且采用模块化设计,api分散在多个对象上,如果要展开的话内容很多,所以大家可以去本章的参考资料中查看,阮一峰大神写的很好了,这里也不多说。链接贴在了最后。
三、目录
参考资料,附:
- https://www.ruanyifeng.com/blog/2020/12/fetch-tutorial.html
- https://www.zhihu.com/question/27771468
- https://xhr.spec.whatwg.org/#the-status-attribute
- https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest
一比一还原axios源码(零)—— 概要的更多相关文章
- 一比一还原axios源码(四)—— Axios类
axios源码的分析,到目前为止,算上第0章已经四章了,但是实际上,还都没有进入axios真正的主线,我们来简单回顾下.最开始我们构建了get请求,写了重要的buildURL方法,然后我们处理请求体请 ...
- 一比一还原axios源码(一)—— 发起第一个请求
上一篇文章,我们简单介绍了XMLHttpRequest及其他可以发起AJAX请求的API,那部分大家有兴趣可以自己去扩展学习.另外,简单介绍了怎么去读以及我会怎么写这个系列的文章,那么下面就开始真正的 ...
- 一比一还原axios源码(三)—— 错误处理
前面的章节我们已经可以正确的处理正确的请求,并且通过处理header.body,以及加入了promise,让我们的代码更像axios了.这一章我们一起来处理ajax请求中的错误. 一.错误处理 首先我 ...
- 一比一还原axios源码(六)—— 配置化
上一章我们完成了拦截器的代码实现,这一章我们来看看配置化是如何实现的.首先,按照惯例我们来看看axios的文档是怎么说的: 首先我们可以可以通过axios上的defaults属性来配置api. 我们可 ...
- 一比一还原axios源码(八)—— 其他功能
到此,我们完成了axios的绝大部分的功能,接下来我们来补全一下其他的小功能. 一.withCredentials 这个参数可以可以表明是否是一个跨域的请求.那这个的使用场景是啥呢?就是我们在同域的 ...
- 一比一还原axios源码(二)—— 请求响应处理
上一章,我们开发了一些简单的代码,这部分代码最最核心的一个方法就是buildURL,应对了把对象处理成query参数的方方面面.虽然我们现在可以发起简单的请求了,但是第一,我们无法接收到服务器的响应, ...
- 一比一还原axios源码(五)—— 拦截器
上一篇,我们扩展了Axios,构建了一个Axios类,然后通过这个Axios工厂类,创建真正的axios实例.那么今天,我们来实现下Axios的拦截器也就是interceptors.我们来简单看下Ax ...
- Axios源码深度剖析 - 替代$.ajax,成为xhr的新霸主
前戏 在正式开始axios讲解前,让我们先想想,如何对现有的$.ajax进行简单的封装,就可以直接使用原声Promise了? let axios = function(config){ return ...
- Axios源码分析
Axios是一个基于promise的HTTP库,可以用在浏览器和node.js中. 文档地址:https://github.com/axios/axios axios理解和使用 1.请求配置 { // ...
随机推荐
- 使用C++开发PHP扩展
目前,PHP编程语言也是相当成熟,各种文档,各种问题,只要Google一下,总有你想要的答案.当然"如何开发PHP扩展"的文章也不少,但是很少有专门来介绍使用C++开发PHP扩展的 ...
- LAMP架构—源码编译安装 (爱情受过伤,为爱跳过鸭绿江)
LAMP架构--源码编译安装 1.LAMP架构概述 2.编译安装Apache httpd 服务 3.编译安装mysql 服务 4.编译安装PHP 解析服务 5.利用LAMP搭建论坛 1.LAMP架构概 ...
- 前端语言之js(对比python快速入门)
昨日内容回顾 浮动 定位 溢出 透明度 模态框 今日内容概要 变量与常量 基本数据类型 数据类型内置方法 函数 常见内置对象 BOM与DOM操作 内容详细 1.变量与常量 # 在JS中声明变量需要使用 ...
- PHP宝典面试笔试题目
PHP宝典面试笔试题目 来自<PHP程序员面试笔试宝典>,涵盖了近三年了各大型企业常考的PHP面试题,针对面试题提取出来各种面试知识也涵盖在了本书. PHP题目 [真题68] ( ) ...
- 2、Golang基础--包的使用、if-else语句、循环、switch语句、数组、切片、可变函数参数、map类型
1 包的使用 // 为了便于组织代码,同一种类型的代码,写在同一个包下,便于管理 // 定义包 -新建一个文件夹 -内部有很多go文件 -在每个go文件的第一行,都要声明包名,并且包名必须一致 -在一 ...
- Solution -「CF 1119F」Niyaz and Small Degrees
\(\mathcal{Description}\) Link. 给定一棵 \(n\) 个结点的树,边有边权,对于每个整数 \(x\in[0,n)\),求出最少的删边代价使得任意结点度数不超过 ...
- 大厂偏爱的Agent技术究竟是个啥
搜索关注微信公众号"捉虫大师",后端技术分享,架构设计.性能优化.源码阅读.问题排查.踩坑实践. hello大家好,我是小楼,今天给大家分享一个关于Agent技术的话题,也是后端启 ...
- IDEA中使用Docker
开发环境 IDEA:2020.3.2 Docker:20.10.12 注意,如果没有开启Docker远程连接,请先开启Docker远程连接. 1. 打开或新建一个Web项目 可参考使用IDEA新建一个 ...
- python中类的调用
1 class Computer: # 创建类,类名首字母大写 2 screen = True # 类的属性 3 4 def start(self): # 创建实例方法,不要漏了 self 5 pri ...
- Visual Studio 2017-2019版本创建C#项目时没有创建网站这一选项?
通过了解以后发现Visual Studio 2017之后的版本在新建选项中已经不再有这一选择项了. 解决办法: 1.在创建新项目的面板滑倒最下面,---> 安装多个人工具和功能 2.这时已经打开 ...