说起浏览器和服务器的通信,最先想到的技术必然就是Ajax了。在ES6中还提供了fetch API,相当于把Ajax用Promise封装起来,看起来更像同步操作了。先大概看下这两种方式:
- ES5中的Ajxa
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState !== 4) {
return;
}
if (xhr.status >= 200 && xhr.status <= 300 || xhr.status === 304) {
alter(xhr.response);
}
}
xhr.open('GET', url, true);
xhr.send();
- ES6中fetch
fetch(url)
.then(response => alter(response))
.catch(e => alert(e));
很明显fetch方法看起来更加简洁,而且fetch也有很多自己很好的特性。想仔细了解fetch的童鞋可以去看看阮一峰老师的博客:Fetch API教程(ps:前端不识阮一峰,学遍技术也枉然)。本篇文章主要是讲ES5中Ajax技术的核心XMLHttpRequst对象的用法(下文都把XMLHttpRequest对象称为XHR对象)以及XHR对象的一些属性。
第一步:new XHR对象
既然要使用XHR对象,当然要先new一个XHR对象了
// new一个XHR对象
let xhr = new XMLHttpRequest();
tip: 对于IE7之前的浏览器会有兼容问题,但我觉得如果现在还有人用IE7之前的浏览器,他也不配用2021年的程序员写的网页。
第二步:为onreadystatechange事件绑定事件处理函数
先说下XHR的readyState属性,该属性表示请求/响应过程的当前阶段,也就是请求/响应事件大概进行到什么程度了。该属性有5个取值:
- 0:未初始化。尚未调用open()方法(下文会介绍)。
- 1:启动。已经调用open()方法,但未调用send()方法(下文会介绍)。
- 2:发送。已经调用send()方法,但未收到响应。
- 3:接收。已经接收到部分信息。
- 4:完成。已经接收到所有信息。
只要readyState的值改变一次,就会触发onreadystatechange事件。也就是说,其实一次的请求/响应会触发4次onreadystatechange事件,但通常情况我们只对完成阶段感兴趣,也就是readyState为4的阶段。然后再说下XHR的另一个属性status。这个属性的值为http请求的响应码,没错,就是那些什么200啊,304啊,404啊,500什么的。还有一个responseText属性,这个属性作为响应主体被返回的文本。明确了这几个概念,就可以为XHR对象的onreadystatechange事件绑定事件响应函数了。
// new一个XHR对象
let xhr = new XMLHttpRequest();
// 为onreadystatechange事件绑定事件响应函数
xhr.onreadystatechange = function () {
// 只有readyState为4的时候我们才处理返回的数据
if (xhr.readyState !== 4) {
return;
}
// 根据status属性(状态码)来决定下一步操作
if (xhr.status >= 200 && xhr.status <= 300 || xhr.status === 304) {
alter(xhr.responseText);
}
};
第三步:调用open()方法
当为onreadystatechange事件绑定事件响应函数后,就要发起请求了。与发起请求有关的第一个函数就是open()。这个函数接收三个参数:
- 请求方式(String类型):'GET'或者其他http请求方式
- url(String类型):请求的地址
- 是否异步处理请求(Boolean类型):如果为true,则在请求的时候继续处理其余脚本(异步)。如果为false,则等请求/响应完成后再处理剩余脚本(同步)。
但要明确一点,调用open()方法以后并没有真正发送请求,而是做好了发送请求的准备。
// new一个XHR对象
let xhr = new XMLHttpRequest();
// 为onreadystatechange事件绑定事件响应函数
xhr.onreadystatechange = function () {
// 只有readyState为4的时候我们才处理返回的数据
if (xhr.readyState !== 4) {
return;
}
// 根据status属性(状态码)来决定下一步操作
if (xhr.status >= 200 && xhr.status <= 300 || xhr.status === 304) {
alter(xhr.responseText);
}
};
// 调用open()方法
xhr.open('GET', url, true);
这个时候大军已经通过open()方法做好出征的准备了,粮草装备什么的都齐全了,就等总指挥下令了,也就是调用send()方法。
第四步:调用send()方法
send()方法就是用来真正发送一个请求。send()方法接收一个对象参数,这个参数就是作为请求体一起发送给服务器(POST方法和GET方法的区别)。如果是使用get请求方式这里直接为空也可以,但是为了兼容有些浏览器最好传一个null。
// new一个XHR对象
let xhr = new XMLHttpRequest();
// 为onreadystatechange事件绑定事件响应函数
xhr.onreadystatechange = function () {
// 只有readyState为4的时候我们才处理返回的数据
if (xhr.readyState !== 4) {
return;
}
// 根据status属性(状态码)来决定下一步操作
if (xhr.status >= 200 && xhr.status <= 300 || xhr.status === 304) {
alter(xhr.responseText);
}
};
// 调用open()方法
xhr.open('GET', url, true);
// 调用send()方法
xhr.send(null);
到此为止,一个XHR对象的Ajax的基本步骤就做完了,至于设置请求头和收到响应后的其他方法,这里就不多做介绍了,最后放一个封装的Ajax函数来结束本篇文章吧
// es5方式
let ajax = {
get: function (url, fn, bool) {
let xhr = new XMLHttpRequest();
// 先绑定事件再调用open方法可以做到向后兼容
xhr.onreadystatechange = handle();
// oepn后并未实际发出请求,而是做一个请求准备
xhr.open('GET', url, bool = true);
xhr.send();
// 每次readyStated的值改变都会触发onreadystatechange事件
function handle() {
// 不为4的时候数据没有全部接收,不能使用
if (xhr.readyState !== 4) {
return;
}
//200:成功获取数据;304:数据没有改变,使用缓存
if (xhr.status === 200 || xhr.status === 304) {
fn.call(xhr.response);
}
}
},
post: function (url, fn, bool) {
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = handle();
xhr.open('POST', url, bool);
xhr.send();
function handle() {
if (xhr.readystate !== 400) {
return;
}
if (xhr.status === 200 || xhr.status === 304) {
fn.call(response);
}
}
}
}