从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分散在多个对象上,如果要展开的话内容很多,所以大家可以去本章的参考资料中查看,阮一峰大神写的很好了,这里也不多说。链接贴在了最后。

三、目录

  1. 一比一还原axios源码(零)—— 概要

参考资料,附:

  1. https://www.ruanyifeng.com/blog/2020/12/fetch-tutorial.html
  2. https://www.zhihu.com/question/27771468
  3. https://xhr.spec.whatwg.org/#the-status-attribute
  4. https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest

一比一还原axios源码(零)—— 概要的更多相关文章

  1. 一比一还原axios源码(四)—— Axios类

    axios源码的分析,到目前为止,算上第0章已经四章了,但是实际上,还都没有进入axios真正的主线,我们来简单回顾下.最开始我们构建了get请求,写了重要的buildURL方法,然后我们处理请求体请 ...

  2. 一比一还原axios源码(一)—— 发起第一个请求

    上一篇文章,我们简单介绍了XMLHttpRequest及其他可以发起AJAX请求的API,那部分大家有兴趣可以自己去扩展学习.另外,简单介绍了怎么去读以及我会怎么写这个系列的文章,那么下面就开始真正的 ...

  3. 一比一还原axios源码(三)—— 错误处理

    前面的章节我们已经可以正确的处理正确的请求,并且通过处理header.body,以及加入了promise,让我们的代码更像axios了.这一章我们一起来处理ajax请求中的错误. 一.错误处理 首先我 ...

  4. 一比一还原axios源码(六)—— 配置化

    上一章我们完成了拦截器的代码实现,这一章我们来看看配置化是如何实现的.首先,按照惯例我们来看看axios的文档是怎么说的: 首先我们可以可以通过axios上的defaults属性来配置api. 我们可 ...

  5. 一比一还原axios源码(八)—— 其他功能

    到此,我们完成了axios的绝大部分的功能,接下来我们来补全一下其他的小功能. 一.withCredentials  这个参数可以可以表明是否是一个跨域的请求.那这个的使用场景是啥呢?就是我们在同域的 ...

  6. 一比一还原axios源码(二)—— 请求响应处理

    上一章,我们开发了一些简单的代码,这部分代码最最核心的一个方法就是buildURL,应对了把对象处理成query参数的方方面面.虽然我们现在可以发起简单的请求了,但是第一,我们无法接收到服务器的响应, ...

  7. 一比一还原axios源码(五)—— 拦截器

    上一篇,我们扩展了Axios,构建了一个Axios类,然后通过这个Axios工厂类,创建真正的axios实例.那么今天,我们来实现下Axios的拦截器也就是interceptors.我们来简单看下Ax ...

  8. Axios源码深度剖析 - 替代$.ajax,成为xhr的新霸主

    前戏 在正式开始axios讲解前,让我们先想想,如何对现有的$.ajax进行简单的封装,就可以直接使用原声Promise了? let axios = function(config){ return ...

  9. Axios源码分析

    Axios是一个基于promise的HTTP库,可以用在浏览器和node.js中. 文档地址:https://github.com/axios/axios axios理解和使用 1.请求配置 { // ...

随机推荐

  1. 记一次.net core 异步线程设置超时时间

    前言: 刷帖子看到一篇 Go 记录一次groutine通信与context控制 看了一下需求背景,挺有意思的,琢磨了下.net core下的实现 需求背景: 项目中需要定期执行任务A来做一些辅助的工作 ...

  2. RPC和REST的区别

    REST定义 REST是一种架构风格,指的是一组架构约束条件和原则.满足这些约束条件和原则的应用程序或设计就是 RESTful.REST规范把所有内容都视为资源,网络上一切皆资源.REST并没有创造新 ...

  3. Spring @Cacheable 缓存不生效的问题

    最近在项目中使用了Ehcache缓存,使用方式是用Spring提供的 @Cacheable 注解的方式,这种方式简单.快速.方便,推荐使用. 在使用的过程中,遇到了缓存不生效的情况,经过分析处理,总结 ...

  4. 在Spring Boot中从类路径加载文件

    介绍 创建Spring Boot Web应用程序时,有时有时需要从类路径中加载文件:war和jar的加载文件格式是不一样的 在下面,您将找到在WAR和JAR中加载文件的解决方案. 资源加载器 使用Ja ...

  5. lua语言:时间

    转载请注明来源:https://www.cnblogs.com/hookjc/ 时间库函数 1.用数值表示时间值 用数字值来表示时间值,实际上时间值的本质就是一个数字值.例如:d = 11312864 ...

  6. request和session获取参数的区别

    说简单点 request对象和session对象的最大区别是生命周期. request request范围较小一些,只是一个请求. request对象的生命周期是针对一个客户端(说确切点就是一个浏览器 ...

  7. iOS中属性 (nonatomic, copy, strong, weak)的使用 By hL

    以下内容来自Stackflow的详解 1.Nonatomicnonatomic is used for multi threading purposes. If we have set the non ...

  8. Python--操作列表

    Python--操作列表 目录 Python--操作列表 一.遍历整个列表 1. 深入研究循环 2. 在for循环中执行更多操作 3. 在for循环结束后执行一些操作 二.避免缩进错误 1. 忘记缩进 ...

  9. 期中架构&防火墙¥四表五链

    今日内容 架构图 包过滤防火墙 Iptables 新建虚拟机 内容详细 一.架构图 用户通过域名访问一个网站类比开车去饭店用餐 访问网站的流程 1.浏览器输入网站的域名(www.baidu.com), ...

  10. Solution -「NWRRC 2017」「洛谷 P7024」Fygon 2.0

    \(\mathcal{Description}\)   Link.   给定一个无并列语句的多重循环,每个变量取值的左端点只能是 \(1\) 或已定义的变量:右端点只能是 \(n\) 或已定义的变量. ...