Blog
Blog copied to clipboard
XMLHttpRequest的五个阶段
我们在使用ajax的时候,出于方便,通常使用jquery的$.ajax()
方法,简单快捷,帮助我们屏蔽了许多底层的细节。久而久之我们很容易就会遗忘掉原生ajax的一些知识点,比如XMLHttpRequest
。下面我就帮助大家对ajax的工作流程梳理一下。
XMLHttpRequest
是ajax实现的基础,我们常常用它来对服务器发送一个异步请求:
//实例化一个XMLHttpRequest对象
const xhr = new XMLHttpRequest();
//onreadystatechange方法:判断当前请求的进度
xhr.onreadystatechange = function() {
//当readyState的值为4时获取返回的值
if(xhr.readyState === 4) {
console.log(xhr.responseText);
}
}
//指定http方法和目标主机,建立连接
xhr.open('GET', 'localhost:8080');
//发送请求
xhr.send();
通常,一次http数据请求,要经过
建立连接 ==> 发送请求 ==> 响应请求 ==> 返回数据
4个阶段,所以说XMLHttpRequest
在获取返回的数据的时候,一定要在特点的阶段获取,不然肯定是获取不了的,很显然xhr.readyState === 4
的时候,是数据返回成功的阶段。那么在其他阶段,xhr.readyState
的值又对应什么呢,我们可以查阅一下MSDN:
可以看到,各个readyState
对应的阶段为:
-
readyState === 0
:XMLHttpRequest
对象初始化(实例化)完成 -
readyState === 1
:open
方法完成(连接建立),未调用send
方法(未发送) -
readyState === 2
:send
方法被调用(发送请求) -
readyState === 3
:已响应,但responseText
不可用(返回的数据未准备好) -
readyState === 4
:所有工作都已完成,responseText
可用
同样的,我们可以很容易想到, onreadystatechange
这个方法肯定不是只被调用一次,而是会被调用多次,在什么时候被调用呢?很明显,是在每次readyState
的值发生更改的时候。
看到这里,相信大家已经对ajax的整个工作流程有一个大概的轮廓了,但是为了加深理解,我们可以按照上面的思路,造一个假的XMLHttpRequest
对象,模拟一下ajax的工作流程。
MyXMLHttpRequest
首先我们要确定我们的MyXMLHttpRequest
对象里面有哪些成员变量和方法:
-
readyState
-
resposeText
-
status
:保存http状态码 -
open
方法 -
send
方法 -
onreadystatechange
方法 -
setReadyState
方法:用作设置readyState
的值
然后就可以一步一步写我们的 MyXMLHttpRequest
类,由于偷懒,我这里就直接放完整代码了:
export default class MyXMLHttpRequest {
public readyState: number;
public responseText: string;
public status: number;
constructor() {
//在初始化对象时设置readyState为0
this.setReadyState(0);
console.log('MyXMLHttpRequest被实例化,readyState值为: ' + this.readyState);
}
/*
* 设置readyState的方法
* @param newState<number> 新的readyState的值
* @return <void>
*/
setReadyState(newState: number): void {
this.readyState = newState;
//每次readyState发生改变都会调用onreadystatechange方法
this.onreadystatechange && this.onreadystatechange();
}
/*
* onreadystatechange方法
*/
onreadystatechange(): void {}
/*
* open方法
* @param httpMethod<string> http请求方式
* @param targetHost<string> 请求的目标主机
* @return <void>
*/
open(httpMethod: string, targethost: string): void {
//请求开启,open方法被调用,readyState设置为1
this.setReadyState(1);
}
/*
* send方法
*/
send(): void {
//send方法被调用,readyState设置为2
this.setReadyState(2);
//模拟响应请求
setTimeout(() => {
//响应成功,readyState设置为3
this.setReadyState(3);
//模拟接收返回的数据
setTimeout(() => {
//http状态码为200,表示请求没有错误
this.status = 200;
//responseText的数据也已经准备完成
this.responseText = 'Phenom';
//所有工作已经完成,readyState设置为4
this.setReadyState(4);
}, 200);
}, 100);
}
}
由于客观原因限制,我们没有办法用浏览器环境下的javascript来真实地进行http请求的发送和接收,所以这段代码是不能真正向服务器发送请求的,但是没关系,那不是重点, 我们主要目的是要搞清楚XMLHttpRequest
在每个阶段做了什么工作。 由于XMLHttpRequest
发送请求是异步的,我们可以用setTimeout来模拟异步的请求流程。
最后我们像普通的ajax操作一样,写我们的代码:
const myXhr = new MyXMLHttpRequest();
myXhr.onreadystatechange = function() {
console.log('当前的readyState值为: ' + myXhr.readyState);
if(myXhr.readyState === 4) {
console.log('responseText的值为: ' + myXhr.responseText);
}
};
myXhr.open('GET', 'localhost:8080');
myXhr.send();
运行结果:
perfect!
总结一下
最后总结一下,XMLHttpRequst
的工作流程为:
-
XMLHttpRequest
对象被初始化,对应的readyState
为0 -
open
方法被调用,启用连接,对应的readyState
为1 -
send
方法被调用,发送请求,对应的readyState
为2 -
响应完成,但
responseText
准备好,对应的readyState
为3 -
responseText
已完成,所有工作都已完成,对应的readyState
为4