说起前端开发,Ajax请求是绕不开的技术点。然而,程序语言更新换代越来越快,Ajax请求的方式也是各有不同。
在使用ES5开发的时候,我们还在使用最原始的XMLHttpRequest对象:
// createXHR函数,返回浏览器支持的异步请求对象
function createXHR() {
if(typeof XMLHttpRequest != "undefined"){
return new XMLHttpRequest(); // IE7+、Firefox、Opera、Chrome、Safari
}
else if(typeof ActiveXObject != "undefined"){
return new ActiveXObject("Microsoft.XMLHTTP"); // IE7及以前版本的浏览器
}
else{
throw new Error("No XHR object available.");
}
}
var xhr = createXHR(); //创建XHR对象
xhr.onreadystatechange = function(){ //readyState状态改变及触发onreadystatechange事件
if(xhr.readyState == 4){ //readyState状态改变可从0到4,4表示所有数据已就绪
if((xhr.status >= 200 && xhr.status <300) || xhr.status == 304){ //status为200,响应成功;status为304,表示请求的资源未被修改
alert(xhr.responseText); //responseText表示响应主体返回的文本
} else {
alert("Request was unsuccessful: " + xhr.status);
}
}
};
xhr.open("get", "test.php?uid=1&name=xiaoming", true); //启动一个请求以备发送
xhr.send(null);
上面是get请求方式。
发送相同量数据时,get比post快得多,所以如无必要,应尽量使用get请求方式。
post可以发送更多的数据,且不限格式。
post请求需要添加额外的请求头,并把发送数据放在send方法中,如:
xhr.open("post", "test.php", true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); // post请求需要设置Content-Type
var form = document.getElementById("user");
xhr.send(serialize(form)); // 假如form是一个表单节点,serialize()序列化了表单数据
/*
假如需要发送的数据是一个对象,如data,也可以使用JSON.stringify(data)把数据字符串化,在使用send()方法发送
*/
后来出现了JQuery ,极大的简化了Ajax请求的代码编写,几乎只需要一行代码。
$.ajax({
url: "demo_test.php",
type: "POST",
data: {name: 'xiaoming'},
success: function(result, status, xhr){
alert(result);
},
error: function(result, status, xhr){
alert('错误:'+status);
}
});
单独使用post请求,也可以写成:
$.post("test.php", {uid:'001'}, function(data,status,xhr){
alert(data);
});
单独使用get请求,也可以写成:
$.get("test.php",{name: 'xiaom'}, function(data,status,xhr){
alert("数据: " + data + "\n状态: " + status);
});
到ES6出现的时候,有了新的对象 Promise ,它带有的then和catch方法可以获取异步执行代码的数据,我们就可以把ajax请求获取的数据取出,做我们想要的操作。
根据需要,我们可以把ajax请求放在一个Promise对象中:
function ajax(URL) {
return new Promise(function (resolve, reject) {
// createXHR函数,返回浏览器支持的异步请求对象
function createXHR() {
if(typeof XMLHttpRequest != "undefined"){
return new XMLHttpRequest(); // IE7+、Firefox、Opera、Chrome、Safari
}
else if(typeof ActiveXObject != "undefined"){
return new ActiveXObject("Microsoft.XMLHTTP"); // IE7及以前版本的浏览器
}
else{
throw new Error("No XHR object available.");
}
}
var xhr = createXHR(); //创建XHR对象
xhr.onreadystatechange = function(){ //readyState状态改变及触发onreadystatechange事件
if(xhr.readyState == 4){ //readyState状态改变可从0到4,4表示所有数据已就绪
if((xhr.status >= 200 && xhr.status <300) || xhr.status == 304){ //status为200,响应成功;
//status为304,表示请求的资源未被修改
resolve(xhr.responseText); //responseText表示响应主体返回的文本
} else {
reject("Request was unsuccessful: " + xhr.status);
}
}
};
xhr.open("get", "test.php?uid=1&name=xiaoming", true); //启动一个请求以备发送
xhr.send(null);
});
}
获得的数据可以使用then和catch方法处理:
ajax('test.php').then((value) => {
alert(value); // 请求成功
}).catch((error) => {
alert(error); // 请求失败
});
也可以使用async和await获取:
async function getData(){
try {
const responceText = await ajax();
alert(responceText);
} catch (error) {
alert(error); //输出异常错误
}
}
getData();
而对于React来说,它是组件化编程方式,如果你想在组件初次渲染时就展示ajax请求获取的数据,我们一般把ajax请求放在生命周期钩子componentDidMount中:
class User extends React.Component {
// ......
componentDidMount() {
// 以JQuery的ajax请求举例
this.serverRequest = $.get('test.php', {uid: '001'},function (result) {
// 用获取的数据更新组件的state数据
this.setState({
username: result.username,
lastTime: result.lastTime
});
}.bind(this));
}
// 组件卸载,销毁未结束的请求
componentWillUnmount() {
this.serverRequest.abort();
}
// ......
}
如果需要用户的操作(如:点击按钮)以获取数据,请将ajax请求放在onClick事件句柄函数中。
新版的React推荐使用函数式组件,那就没有生命周期函数了,一般把第一次渲染后需要的ajax请求放在React Hook Effect中:
import { useEffect, useState } from 'react';
const [username, setUsername] = useState('');
const [lastTime, setLastTime] = useState('');
// 在开发环境,组件渲染之后,Effect会执行两次,第一次是调试
// 为了不更新两次数据,需要设置清理函数
// 在生产环境,Effect只会执行一次
useEffect(() => {
let ignore = false;
// 以JQuery的ajax请求举例
// 如果是初次请求,ajax请求数据,更新state
if(!ignore){
$.get('test.php', { uid: '001' },function (result) {
setUsername( result.username );
setLastTime( result.lastTime );
});
}
// 清理函数,第一次请求之后,把ignore设为true,第二次请求时不会再获取数据
return () => {
ignore = true;
};
}, [userId]);