AJAX 全称 Async JavaScript And XML ;主体思想就是使用 JS 发请求和收响应。

背景

在网页开发中,浏览器与服务器之间使用 HTTP 通信。浏览器输入一个地址,或者通过 form 表单发送数据。这时浏览器就会向服务器发出 HTTP 请求。
1999年,微软发布的 IE 5.0 首次引入该功能,但是没有能够引起重视。2004年,Gmail发布;2005年,Gmap发布。两个现象级产品正式把 AJAX 带入了人们的眼界。AJAX 一开始是用来处理 XML 的,直到后续出现的 JSON 发展到今天的 AJAX 可以处理如:HTML/CSS/JS/XML/JSON等。
2006年,W3C 发布了 AJAX 的国际标准。

步骤

AJAX 包括以下几个步骤:

  1. 创建 XMLHttpRequest 实例。
  2. 发出 HTTP 请求。
  3. 接收服务器传话的数据。
  4. 更新网页数据。

总体来说,浏览器创建了一个 XMLHttpRequest 函数,用这个函数可以构造出一个对象,JS 通过这个对象进行数据的发送与接收。这就是 AJAX。
AJAX 之所以用途如此之广,则还有一个特点:从服务器拿到数据后,并不会刷新整个网页,而是只更新网页里面的相关部分,从而不打断用户正在做的事情。
注意:AJAX 只能请求同源的网址(同源:同协议、同域名、同端口),如果是跨域请求,则需要做一些特别的处理,详情查看后续文章。
AJAX 完整例子:

// 创建实例
const request = new XMLHttpRequest()
// 建立连接
request.open('GET', '/xxx')
// 检测是否成功
request.onreadystatechange = function () {
	if (request.readyState === 4) {
  	if (request.status >= 200 && request.status < 300) {
    	success()
    } else {
    	error()
    }
  }
}
// 发送
request.send()

XMLHttpRequest 实例属性

readyState

readyState 返回一个整数,表示实例对象的当前状态。是只读属性,不可写。有如下值:

  • 0,表示 XMLHttpRequest 实例已经生成。
  • 1,表示 open() 方法已经被调用了。但是可以使用 setRequestHeader() 方法来设置请求头。
  • 2,表示 send() 方法被调用。
  • 3,表示正在接收服务器返回的数据。
  • 4,表示服务器返回的数据已经被完全接收,或者接收失败。

在通信的过程中,每当实例对象的状态变化,都可以触发 readyState 值的变化。这个值的变化则可以通过一个叫 readyStatechange 事件监听到。如下:

const request = new XMLHttpRequest()
if (request.readyState === 4) {
  // 请求结束,可以处理数据
} else {
	// 请求中
}

onreadystatechange

上文中我们提到过,如果要监听 readyState 的变化,则可以使用 readystatechange 事件实现监听。

response

XMLHttpRequest.response 属性表示服务器返回的数据体。可以是任何的数据类型,如:字符串、对象、二进制对象等,当然平时工作中用到最多的还是对象,具体的类型可以由 XMLHttpRequest.responseType 属性决定的。该属性时只读的属性。

responseType

XMLHttpRequest.responseType 属性表示服务器返回数据的类型,是一个字符串。这个属性时可写,可以在 open() 方法之后 send() 方法之前,设置该属性值,告诉服务器我需要什么样的数据。如果设置 responseType 为空字符串,则默认的类型则是 text 。可以有以下值:

  • ”” 空字符串,表示服务器返回文本数据。
  • “arraybuffer” 表示服务器返回二进制数组。
  • “blob” Blob 对象,表示服务器返回二进制对象。(主要用在图像上)
  • “json”, 返回 JSON 对象。
  • “text”, 返回字符串。
  • “document” 返回文档。

    const request = new XMLHttpRequest()
    request.open('GET', '/xxx')
    request.responseType = 'json'
    request.onreadystatechange = function () {
    	if (request.readyState === 4 && request.states === 200) {
    	success()
    }
    }
    

responseText

该属性接收服务器返回的字符串,为只读属性。只有请求完成后,该属性才会包含完整的数据。

responseXML

该属性返回从服务器接收到的 XML 或 HTML 文档对象,为只读属性。如果本次请求没有成功,或者收到的数据不是 XML 或 HTML 则返回的是 null 。
当然,如果要使用该属性的话是有限制条件的。必须把 HTTP 的回应头 Content-Type 设置为 text/xml 或 application/xml 。而且在发送请求时把 request.responseType 设置为 document 。当然如果返回头不是 text/xml 和 application/xml 又想通过此属性获取,则可以通过调用 XMLHttpRequest.overrideMimeType() 方法,强制进行 XML 解析。该属性成功解析后,就会形成一个 DOM 文档树。

status

该属性返回一个整数,表示服务器 HTTP 请求后的状态码。一般来讲如果通信成功,状态码则为 200,该属性时只读的,有如下常见的状态码:

  • 200 表示正常,请求成功。
  • 301,永久移动。
  • 302,暂时移动。
  • 304,MDN 解释,如果客户端发送了一个带条件的 GET 请求且该请求已被允许,而文档的内容(自上次访问以来或者根据请求的条件)并没有改变,则服务器应当返回这个状态码。304 响应禁止包含消息体,因此始终以消息头后的第一个空行结尾。
  • 307,暂时重定向。
  • 401,未授权。
  • 403,禁止访问。
  • 404,找不到指定的地址。
  • 500, 服务器发生了错误。

只有状态码是 2xx 与 304 表示服务器返回是正常状态。

timeout 与 ontimeout

timeout 属性返回一个整数,表示多少毫秒后,如果请求仍然没有得到结果,就会自动终止。如果该属性为 0,就表示没有时间限制。
ontimeout 属性用于设置了一个监听函数,如果发生了 timeout 事件,就会执行这个监听函数。例子如下:

const request = new XMLHttpRequest()
request.open('GET', '/xxx')
request.ontimeout = function () {
	console.error('超时了')
}
request.onreadystatechange = function () {
	if (request.readyState === 4 && request.status === 200) {
  	success()
  } else {
  	error()
  }
}
// 设置请求时间为10s
request.timeout = 10 * 1000
request.send()

upload

XMLHttpRequest 不仅可以发送请求,还可以发送文件,这就是 AJAX 文件上传。当我们发送一个文件后,可以通过 XMLHttpRequest.upload 属性得到一个对象,通过这个对象的事件,则可以得到上传文件的进展。主要事件有: loadstart loadend load abort error progress timeout 。

XMLHttpRequest 的实例方法

open() 

该方法用于指定 HTTP 请求的参数,主要用到的参数是 method 与 url

  • method : 表示 HTTP 动词方法,比如: GET / POST / PUT / DELETE HEAD 等。在传参是最好是全大写或者全小写,切不可又大写又小写。
  • url : 表示请求发送目标 URL

    send()

    该方法用于实际发出的 HTTP 请求。它的参数是可选的,如果不带参数代表 HTTP 请求中只有一个 URL 没有数据体,如: GET 请求,如果带着参数,则表示在请求时带有数据信息体,如: POST 请求。

  • GET 请求示例:

    const request = new XMLHttpRequest()
    request.open('GET', '/xxx?id=' + encodeURIComponent(id))
    ...
    request.send()
    
  • POST 请求示例

    const request = new XMLHttpRequest()
    const data = 'email='
    + encodeURIComponent(email)
    + '&password='
    + encodeURIComponent(password)
    request.open('POST', '/xxx'))
    ...
    // 指定为form表单方式提交
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
    xhr.send(data)
    

注意:所有的 XMLHttpRequest 的监听事件,都必须在 send() 方法调用之前设定。

  • formData 发送数据

    const formData = new FormData()
    
    formData.append('username', '小鱼儿')
    formData.append('email', 'xiaoyuer@126.com')
    formData.append('password', 'xxxxxx')
    
    const request = new XMLHttpRequest()
    request.open('POST', '/xxx')
    request.send(formData)
    

setRequestHeader

该方法用于设置浏览器发送的 HTTP 请求的头信息。必须在 open() 之后 与 send() 之前调用。如果该方法多次调用,设定的同一个字段,则每一次调用的值都会被合并成一个单一的值发送。

abort

该方法用于终止已经发出的 HTTP 请求。调用此方法后, readyState 变为 4  status 变为 0。

const request = new XMLHttpRequest()
request.open('GET', '/xxx')
setTimeout(() => {
  if (request) {
  	request.abort()
    request = null
  }
}, 4000)

// 4s 后终止请求

参考资料