从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. StarUML官网地址 http://staruml.io/

    StarUML官网地址 http://staruml.io/

  2. 电脑预装Office2016打开Word时点击保存弹出“word无法启动转换器RECOVR32.CNV”对话框问题的修复方法

    感谢大佬:https://blog.csdn.net/qq_41969790/article/details/85161701 1.问题描述:电脑预装的Office2016,家庭和学生版正版.每次打开 ...

  3. linux 设置connect 超时

    转载请注明来源:https://www.cnblogs.com/hookjc/ 将一个socket 设置成阻塞模式和非阻塞模式,使用fcntl方法,即: 设置成非阻塞模式: 先用fcntl的F_GET ...

  4. C语言中的单引号和双引号的区别

    首先肯定地说,二者是有区别的,不是说用谁都一样. 1.实质区别,代表的含义不同 'A'代表的是一个整数,而且这个整数对应的是编译器所采用的字符集中的字符序列对应的数值.所以'A'跟ASCII中的65意 ...

  5. Haproxy配合Nginx搭建Web集群部署

    Haproxy配合Nginx搭建Web集群部署实验 1.Haproxy介绍 2.Haproxy搭建 Web 群集 1.Haproxy介绍: a)常见的Web集群调度器: 目前常见的Web集群调度器分为 ...

  6. MHA高可用配置及故障切换

    MHA高可用配置及故障切换 目录 MHA高可用配置及故障切换 一.案例概述 二.案例前置知识点 1. MHA概述 2. MHA的组成 (1)MHA Manager(管理节点) (2)MHA Node( ...

  7. MySQL5.7修改登录密码的几种方式

    1.更新mysql.user表 use mysql UPDATE user SET authentication_string = password('新密码') where user = 'root ...

  8. SpringMVC 解析(三) Controller 注解

    我在前面的文章中介绍了Spring MVC最核心的组件DispatcherServlet,DispatcherServlet把Servlet容器(如Tomcat)中的请求和Spring中的组件联系到一 ...

  9. ConcurrentHashMap (jdk1.7)源码学习

    一.介绍 1.Segment(分段锁) 1.1 Segment 容器里有多把锁,每一把锁用于锁容器其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效的提高并 ...

  10. 【摸鱼神器】UCode Cms管理系统 内置超好用的代码生成器 解决多表连接痛点

    一.序言 UCode Cms管理系统是面向企业级应用软件开发的脚手架.当前版本1.3.4.快速体验: git clone https://gitee.com/decsa/demo-cms.git (一 ...