1. Intro

1.1 什么是 AJAX

AJAX(Asynchronous JavaScript And XML)is a developer‘s dream.

它并不是一门编程语言,而是一系列技术的整合,包括:

  • 浏览器内置的 XMLHttpRequest 对象(从服务端请求数据)
  • JavaScript 和 HTML DOM(展示或使用数据)

它的作用简单来说就是可以在不重新加载网页的情况下,实现网页内容的局部刷新。由于使用了异步机制,也不会阻塞其他操作的进行。

AJAX 这个名字本身是具有误导性的,因为乍一看认为数据传输使用的是 XML 格式,但实际上现在使用普通文本格式和 json 格式也是同样的常见。

1.2 AJAX 的工作原理

图片.png
从原理图可以看到它的工作流程分以下几步:

  1. 由客户端某个事件触发
  2. 创建一个 XHR 对象,并通过该对象向服务器发送请求
  3. 服务端处理该请求,并将响应结果回送给客户端
  4. 客户端使用 JS 来处理返回的数据,并更新页面的内容

2. XHR 对象

XHR 对象是 AJAX 技术的基石,所有的现代浏览器都支持该对象(build-in)。该对象能够在后台与服务端进行数据的交换,这意味着它可以在不重新加载页面的前提下改变网页的部分数据。

创建该对象的语法为:

  1. 语法:
  2. var = new XMLHttpRequest();
  3. 举例:
  4. xhttp = new XMLHttpRequest();

3. AJAX Request

使用 XHR 对象的 open() 和 send() 方法来向服务端发送一个请求。以下是一个例子:

  1. xhttp.open("GET", "ajax_info.txt", true);
  2. xhttp.send();
Method Description
open(method, url, async) 具体说明了请求的类型

method: 请求类型(GET OR POST)
url: 服务器或文件的位置
async: true 代表异步请求,反之则为同步
send() 向服务端发送请求(用于 GET)
send(string) 向服务端发送请求(用于 POST)

GET or POST?

GET 与 POST 比起来更加的快速和简单,在大多数场景下都可以使用。但是在某些场景下,需要用 POST:

  • 发送大量数据给服务端时(因为 POST 请求没有长度的限制)
  • 发送用户输入,POST 相比 GET 更加的安全和健壮
  • 缓存文件不是一个选项(因为 POST 可能会更新服务端的文件或数据库)

onreadystatechange 属性

使用 XHR 对象,可以定义一个在请求收到答复时要执行的函数,该函数定义在 XHR 对象的 onreadystatechange 属性中。

  1. xhttp.onreadystatechange = function() {
  2. if (this.readyState == 4 && this.status == 200) {
  3. document.getElementById("demo").innerHTML = this.responseText;
  4. }
  5. };
  6. xhttp.open("GET", "ajax_info.txt", true);
  7. xhttp.send();

4. AJAX Response

XHR 对象拥有一些属性,介绍如下:

Property Description
onreadystatechange 该属性定义了一个函数,该函数在 readyState 属性发生变化时被调用
readyState 保存 XHR 对象的状态
- 0:请求未被初始化
- 1:与服务端的连接建立了
- 2:请求被服务端收到了
- 3:处理请求
- 4:请求完成了并且响应就绪了
status
- 200:OK
- 403:Forbidden
- 404:Page not found
statusText 返回状态码所对应的文案,比如 “OK”、”Not Found”

接下来用一个示例讲解 Response 的相关内容:

  1. function loadDoc() {
  2. var xhttp = new XMLHttpRequest();
  3. xhttp.onreadystatechange = function() {
  4. if (this.readyState == 4 && this.status == 200) {
  5. document.getElementById("demo").innerHTML =
  6. this.responseText;
  7. }
  8. };
  9. xhttp.open("GET", "ajax_info.txt", true);
  10. xhttp.send();
  11. }

在该函数中,首先创建了一个 XHR 对象,接着定义了一个函数并赋给 XHR 对象的 onreadystatechange 属性。该函数会在 XHR 对象的 readyState 属性改变时被调用,接着的第 9-10 行就是设置请求的类型并且发送请求。接下来发生的事就很好理解了,服务端会接收到该请求并进行处理,处理完成生成 response 对象后,XHR 对象的 onreadystatechange 属性就会发生变化,如果满足代码中第 4 行的判断条件,就会将服务端的响应内容赋给一个元素的 innerHTML,从而实现了网页部分内容的更新。

当然,XHR 对象的属性远不止上面说到的这些,如果需要进一步的了解,请移步这里

4.1 使用回调函数

一个回调函数会被当做参数传给另一个函数。 如果在一个网站中,存在不止一个 AJAX 任务,那么就应该创建一个函数来处理 XHR 对象,并且对每一个 AJAX 任务编写一个回调函数。

函数的调用需要包含 URL 和当响应就绪后应该调用的回调函数。

上面说的比较抽象,举例来说明它的运行机制。比如在一个网页中,有左右两个按钮(button1 和 button 2),当分别点击这两个按钮时,对应的区域会展示不同的文案,此时使用 AJAX 怎么处理呢?首先肯定会有如下的一段代码:

  1. <button type="button" name="button1" onclick="loadDoc()">
  2. <button type="button" name="button1" onclick="loadDoc()">
  3. 上面代码是我瞎写的,但是大概意思就是对应不同的 button,当点击时,都触发了 loadDoc() 这个函数。

此时,如果 loadDoc() 函数没有任何参数,就像之前只有一个 AJAX 任务那样,那么就会引发问题了。

  1. function loadDoc() {
  2. var xhttp = new XMLHttpRequest();
  3. xhttp.onreadystatechange = function() {
  4. if (this.readyState == 4 && this.status == 200) {
  5. document.getElementById("demo").innerHTML = this.responseText;
  6. }
  7. };
  8. xhttp.open("GET", "ajax_info.txt", true);
  9. xhttp.send();
  10. }
  11. 如果不带参数,那么点击不同的按钮,实际上都是进行了相同的处理...因为当服务端响应就绪后,返回来的处理方式只有一种,就是 onreadystatechange 属性对应的函数定义。

如果想要点击不同的按钮展示不同的内容,必然需要由两个函数分别去处理,即代码长下面这样:

  1. function loadDoc(url, cFunction) {
  2. var xhttp = new XMLHttpRequest();
  3. xhttp.onreadystatechange = function() {
  4. if (this.readyState == 4 && this.status == 200) {
  5. cFunction(this);
  6. }
  7. };
  8. xhttp.open("GET", url, true);
  9. xhttp.send();
  10. }
  11. function myFunction1(xhttp){
  12. do something;
  13. }
  14. function myFunction2(xhttp){
  15. do something;
  16. }

第 12 和 16 行分别定义了两个函数,代表着点击不同按钮时分别执行的操作,那么 loadDoc 怎么知道要调用哪个呢,当然是将函数作为参数传到 loadDoc() 中了。由于是在服务端响应就绪返回后调用的函数,因此自定义的这俩也叫回调函数

那么为什么要有 url 参数呢,废话,除非你请求的一直是同一个 location。那么为什么不写多个 loadDoc() 函数呢,当然可以,但是不符合复用原则,闲的蛋疼,徒增代码量。

4.2 服务端响应的属性和方法

服务端响应的属性有:

  • responseText - 以字符串的方式获取 server 的响应
  • responseXML - 以 xml 数据格式的方式获取 server 的响应

服务端响应的方法有:

  • getResponseHeader() - 获取指定的响应头信息
  • getAllResponseHeaders() - 获取所有的响应头信息