一比一还原axios源码(零)—— 是结束亦是开始

从vue2版本开始,vue-resource就不再被vue所维护和支持,官方也推荐使用axios,所以,从我使用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;

   跑起来后我们发现一个问题。诶?怎么会这样?

<span role="heading" aria-level="2">一比一还原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源码(一)—— 发起第一个请求 
  2. 一比一还原axios源码(二)—— 请求响应处理
  3. 一比一还原axios源码(三)—— 错误处理
  4. 一比一还原axios源码(四)—— Axios类
  5. 一比一还原axios源码(五)—— 拦截器
  6. 一比一还原axios源码(六)—— 配置化
  7. 一比一还原axios源码(七)—— 取消功能
  8. 一比一还原axios源码(八)—— 其他功能

四、阶段闲聊

  终于,写完了整个axios的实现,写完了之后发现其实axios的实现源码并不是十分复杂,但是需要一定的了解和熟悉,需要一定的阅读理解能力。我就不多说了,最后说说这一系列的文章吧。首先,整个zaking-axios的example部分的代码,来源于慕课网《下一代前端开发语言 TypeScript从零重构axios》这个视频课,ustbhuangyi老师讲的真的很好。我在学习的过程中就想自己实现一遍,但是课程中有些代码是经过老师优化的,并且加上了ts、jest等。一方面由于我的水平有限,另外一方面我又希望可以让初学者更容易学习,所以,整个zaking-axios并没有加那么多,你只要有基本的js基础,就能看懂我写的zaking-axios。当然,或许后面时间充足,我也会加上ts和jest,也会尽我所能的去优化其中的代码。

  最后,希望大家在阅读的过程中有什么疑问或者发现了什么问题,都可以及时交流,我也会尽快回复。

  最后的最后,感谢!

参考资料,附:

  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
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/124350.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • kafka删除topic数据[通俗易懂]

    kafka删除topic数据[通俗易懂]kafka删除topic数据一、概述生产环境中,有一个topic的数据量非常大。这些数据不是非常重要,需要定期清理。要求:默认保持24小时,某些topic需要保留2小时或者6小时二、清除方式主要有3个:1.基于时间2.基于日志大小3.基于日志起始偏移量详情,请参考链接:https://blog.csdn.net/u013256816/article/details/80418297接下来,主要介绍基于时间的清除!kafka版本为:2.11-..

    2022年10月17日
  • pycharm代码特效插件_pycharm插件在哪

    pycharm代码特效插件_pycharm插件在哪相信对于不少的Python程序员们都是用Pycharm作为开发时候的IDE来使用的,今天小编来分享几个好用到爆的Pycharm插件,在安装上之后,你的编程效率、工作效率都能够得到极大地提升…

  • 软件工程与软件测试_软件工程导论(第六版)

    软件工程与软件测试_软件工程导论(第六版)1.软件测试基础2.单元测试3.集成测试4. 确认测试5.白盒测试技术6.黑盒测试技术7.调试8.软件可靠性

  • springboot 406错误 produces(springboot下载)

    Springboot406错误简单的写了一个接口,然后406了。。。。publicclassTestController{@GetMapping(“/testGet/{message}”)publicResulttestGet(@PathVariableStringmessage){returnResult.success(message);}}Resolved[org.springframework.web.HttpMedi

  • 怎么新建pytest的ini文件_pytest conftest.py文件

    怎么新建pytest的ini文件_pytest conftest.py文件前言pytest配置文件可以改变pytest的运行方式,它是一个固定的文件pytest.ini文件,读取配置信息,按指定的方式去运行查看pytest.ini的配置选项pytest-h找到以下

  • unityshader教程_unity炫酷的shader

    unityshader教程_unity炫酷的shader参考链接:http://www.xiaobao1993.com/373.html去色shader:Shader”Custom/Gray”{ Properties { _MainTex(“Base(RGB)”,2D)=”white”{} }SubShader{Pass{C

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号