說起前端開發,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]);
浙公網安備 33010602011771號