阅读顺序推荐:

  1. 异步的概念
  2. 本文
  3. 异步的实现方式

    两端的概念

Ajax - 图1

简介

全称 Asynchronous Javascript And XML (即:异步的 JavaScript 和 XML)是一个实现与服务器异步通信、局部刷新页面的技术。不会阻塞后面的代码执行,这就是 Ajax 的核心所在。

  • synchronous: 异步的,即在发送数据请求时,程序不用停下来等待响应。或者说执行 ajax 请求时不会阻塞后面代码的运行
  • JavaScript: 使用 js 实现浏览器与服务器间的数据交互
  • XML:一种数据结构,现在已经被 JSON 数据结构取代

在 Ajax 技术出现之前,客户端与服务端之间传输数据都是通过 form 表单。
iShot2021-10-27 11.43.40.png
在 web 应用程序中用户通过表单提交自己输入的信息,服务端的程序接收到用户提交的表单以后根据表单的数据内容进行处理,再把处理结果返回给用户。这就完成了一个简单的交互。

但这种数据传输方式存在一个很大的弊端:每一次用户与服务器的交互都需要重新刷新整个页面。

1999 年微软在 IE5 中新增了一个功能,允许浏览器中的 XMLHttpRequest 对象向服务器发起 http 请求。在当时并没有引起注意,直到 2005 年 Google 发布 Gmail 才发展起来,仅获取数据片段,就能“更新”用户界面,增强了用户体验,于是 Ajax 这个词第一次被正式提出,成为了由脚本发起 http 通信的代名词,2006 年 W3C 发布了国际标准。

Ajax 适用场景:搜索引擎搜索、地图等

Ajax - 图3

Ajax 不是一门新的语言或技术,而是一门当时已经存在的一系列技术的整合。

生活中的委派

在网络请求中委派 XML 对象去服务器取回数据,就不会影响用户同时做其他操作,就好比是直播达人李佳琪当前需要去仓库取回一支口红来做推广。如果李佳琪本人在直播时亲自去仓库,那么所有的观众(看直播的人叫观众吗????)就会一直在屏幕前等待,直到李佳琪本人回来。
但如果李佳琪指派小助手去仓库取货物,那么小助手在去取回口红的过程中,观众就还可以看李佳琪做其他的事情。

那么在网络请求中,小助手就是 XML 对象,去服务器(仓库)取回口红(数据),观众(用户)同时还可以观看其他内容。

优缺点

优点:

  1. 页面无刷新,在页面内与服务器通信减少用户等待时间增强交互体验
  2. 使用异步方式与服务器通信响应速度快
  3. 可以把一些原本由服务器的工作转接到客户端,利用客户端闲置的能力来处理,减轻服务器、宽带的负担
  4. 基于标准化的并被广泛支持的技术,无需下载插件或小程序

缺点:

  1. 无法支持浏览器的页面后退
  2. 对搜索引擎的支持较弱
  3. 影响程序中的异常处理机制

工作原理概述

原生 Ajax 包括以下 4 个步骤

  1. 创建一个 XMLHttpRequest 对象 【创建 xhr 对象】

xhr1.jpeg

  1. 打开链接(打开客户端和服务器端的链接)【派 xhr 去服务器拿数据】

xhr2.jpeg

  1. 发送 http 请求,有数据就发送数据 【xhr 取回数据】

xhr3.jpeg

  1. 处理服务端返回回来的消息【更新网页数据】

xhr4.jpeg

概括起来就是:Ajax 通过原生的 XMLHttpRequest 对象发出 http 请求,得到服务器返回的数据以后,进行处理。

具体过程

1: 创建 XMLHttpRequest 对象

Ajax 的核心技术是 XMLHttpRequest 对象,IE5 是第一款引入 xhr 对象的浏览器,通过 new ActiveXObject() 对象实现,而 IE7+ 及现代浏览器都支持原生的 xhr 对象。

创建一个 XMLHttpRequest 对象也叫 “实例化一个 XMLHttpRequest 对象”,因为 XMLHttpReque() 本身就是一个构造函数:

  1. let xhr = new XMLHttpRequest(); // 1.实例化 xhr 对象

如果要处理低版本 IE 兼容:

  1. let xhr;
  2. if (window.XMLHttpRequest) { // 现代浏览器
  3. xhr = new XMLHttpRequest();
  4. } else { // IE6-
  5. xhr = new ActiveXObject("Microsoft.XMLHTTP");
  6. }
  7. // 写成三目
  8. let xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");

2: 打开链接

xhr 实例对象提供了一个 open() 方法用于打开客户端与服务端间的连接,该方法规定了请求的类型、路径、处理方式是否为异步:

  1. xhr.open(method, url, async); // 默认 true 为异步

参数说明:

  • method:发送请求的方式。(”GET” 和 “POST” 建议大写)
    • GET 用于常规请求,适用于只是从服务器请求需要的资源,只接受 256 字节
    • POST 常用于 HTML 表单,在请求主体中包含额外数据,且这些数据常存储到服务器上的数据库中
  • url:请求资源的位置路径
  • async:默认 true,以异步方式处理。通常来讲都会以异步方式处理,否则 Ajax 将变得毫无意义
  1. xhr.open("GET", "./data.json", true);

3: 发送请求

xhr 实例对象提供了一个 send() 方法用于客户端向服务端发送请求。接收一个参数,即:要作为请求主体发送的数据。调用该方法后,请求被分派到服务器。

  • GET 方式发送,数据被拼接在 open() 方法的 url 中
  • POST 数据则在请求体里。

  • 若请求方式为 GET,send() 方法无参数,或参数为 null

    1. xhr.open("GET", "./data.json");
    2. xhr.send(); // 或 xhr.send(null)

如果还有需要传递的数据,则拼接在 url 后

  1. xhr.open("GET", "./data.json?name=zhangsan&password=123");
  2. xhr.send(); // 或 xhr.send(null)
  • 若请求方式为 POST,send() 的参数为要发送的数据,并添加上请求头 setRequestHeader()
    1. xhr.open("POST", "./data.json");
    2. xhr.setRequestHeader("Context-Type","application/x-www-form-urlencoded;charset=UTF-8");
    3. xhr.send("name=zhangsan&pwd=123");

GET 对比 POST:
与 POST 相比,GET 的请求方式更简单也更快,并且在大部分情况下都能使用。但是,在以下情况中,请使用 POST 请求:

  1. 无法使用缓存文件(更新服务器上的文件或者数据库)
  2. 向服务器发送大量数据(POST 没有数据量的限制)
  3. 发送包含未知字符的用户输入时,POST 更加安全

4. 处理服务端返回的消息

通过 xhr 提供的 onreadystatechange() 事件来监听并处理服务器返回的消息:

  1. xhr.onreadystatechange = function(){...}

这里还有 3 个服务器响应属性值得被关注:

  1. responseText: 译为回应(响应)文本。即作为响应主体被返回的文本(即 xhr 从服务器取回的数据)
  2. status: 译为情况、状况。记录了 http 请求状态码(数字形式)
  3. readyState: 译为准备状态。即 http 请求状态值(记录就绪状态)

readyState

每执行一个任务, readyState 属性都会发生改变。只要 readyState 发生改变,就会触发 onreadystatechange 事件(即 onreadystatechange 事件被触发 5 次(0 - 4),对应着 readyState 的每个变化)

当 readyState 的值为:

0:请求未初始化,即还没有调用 send( ) 方法 1:服务器连接已建立,即已调用 send( ) 方法,正在发送请求 2:请求已接收,即 send( ) 方法执行完成 3:请求处理中,即正在解析响应内容 4:请求已完成,响应已就绪。即响应内容解析完成,可以在客户端进行调用了

也就是说只有当状态值为 4 时,才表示请求完成,所以我们最关心的也就是 readState == 4

status

同 readyState 相似,每一次状态的改变,status 的值也会发生改变

常见状态码:

  • 200:OK 成功
  • 304:not modified 客户端已经执行了 get,但文件未变化
  • 404:not fond 表示 没有发现文件、查询或 URl (没有找到指定的资源)
  • 500:internal server error 服务器内部发生错误,无法完成请求响应
  • 501:not implemented 服务器不支持请求的功能

就是说,当请求状态为 200 时即为请求成功,所以我们最关心的也就是 status == 200

responseText

该属性接收从服务端返回(取得)的数据

  1. let data = xhr.responseText; // data 就是返回的数据

整合代码

将上面的几个步骤整合在一起就能得到完整的 Ajax 请求代码了:

  1. // 1. 创建 xhr
  2. let xhr = new XMLHttpRequest(); // 这里没做低版本 IE 兼容
  3. // 2. 打开连接
  4. xhr.open("GET", "./data.json?name=zhangsan&password=123",true);
  5. // 3. 发送请求
  6. xhr.send();
  7. /*
  8. 如果为 POST 请求
  9. xhr.send('./data.json?name=zhangsan&password=123');
  10. */
  11. // 4. 处理
  12. xhr.onreadystatechange = function () {
  13. if(xhr.readyState == 4 && xhr.status == 200){ // 状态 4 为完成、status 状态码 200 为成功
  14. let data = xhr.responseText; // 获取到从服务端的数据
  15. console.log(data);
  16. }
  17. }

一个测试

假设当前存在一个测试页面 test.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>Document</title>
  8. </head>
  9. <body>
  10. <h1>一个测试页面</h1>
  11. </body>
  12. </html>

有另一个文件去测试请求,当按钮点击,去请求这个 text.html:

<input type="button" value="获取数据">

<script src="https://cdn.bootcdn.net/ajax/libs/Mock.js/1.0.1-beta3/mock-min.js"></script>
<script>
  const btn = document.querySelector('[type="button"]');
  btn.onclick = function () {
    let xhr = new XMLHttpRequest();
    xhr.open('GET', './test.html');
    xhr.send();
    xhr.onreadystatechange = function () {
      if (xhr.readyState == 4 && xhr.status == 200) {
        let data = xhr.responseText;
        console.log(data);
      }
    }
  }
</script>

点击获取.gif

如果要使用 Ajax 发送请求 + Mock 拦截,去 Mock 看看

一个题外话,有关 HTTP

HTTP 全称 hypertext transport protocol 也就是超文本传输协议,它规定了浏览器和万维网服务器之间的通信规则。或者说它就是个约定、规则。

就好比是法外狂徒张三,操着一口流利的四川周边方言,跟一个来自地标建筑为小蛮腰的靓仔李四面对面聊天。语言不互通,这天儿是没法聊的。那如果他们都约定好使用普通话,那交流起来就没啥障碍了。

所以 HTTP 就是这种约定,主要约定了请求和相应。

  • 浏览器发给服务端的称为请求
  • 服务端回来的数据结果称为响应
  • 发送内容叫作请求报文,响应结果叫作响应报文

请求报文包含了:

  1. 请求行
  2. 请求头
  3. 空行
  4. 请求体

请求行 规定了请求方式,GET 或 POST 或其他,当有内容被请求,在地址栏会见到很多的参数,这些参数就由游览器自动拼接好报文内容,拼接在 url 部分,后面还包括了 HTTP 的版本号

iShot2021-10-27 23.13.57.png

请求头和空行 略,内容根据请求内容不同而不同。 请求体 由请求方式决定是否有值,GET 请求为空或 null,POST 请求则有值

响应报文包含了:

  1. 响应行
  2. 响应头
  3. 空行
  4. 响应体

响应行 包含了协议版本 响应状态码(就是那个 status 200 或其他) 响应头和空行 格式同请求头相同 响应体 就是请求回来的内容

好了不要跑远了,就这。