jQuery Ajax、fetch 和 axios
前言
近年來,前端技術(shù)呈現(xiàn)一派迅猛發(fā)展的態(tài)勢,隨之而來的是,前后端通信方式也發(fā)生了翻天覆地的變化,從一開始的重載頁面的老舊方式,逐步發(fā)展到如今 XMLHttpRequest 和 fetch。相應(yīng)的,各種各樣的 Ajax 類庫推陳出新,不斷的進(jìn)步。這個章節(jié),我們打算來聊一聊 jQuery Ajax、fetch和 axios,相信同學(xué)們將會有一個更加全面的了解。
1.jQuery Ajax
這個技術(shù)在前面章節(jié)有獨(dú)立章節(jié)進(jìn)行講解。事實上,$.ajax
是基于原生 XMLHttpRequest
進(jìn)行了封裝,并且提供了一套高度統(tǒng)一的設(shè)計和編程接口。在我們的代碼中,我們一般都這樣寫:
$.ajax({
method: 'POST',
url: url,
data: data,
success: function () {},
error: function () {}
});
或者結(jié)合 deferred 的寫法:
$.ajax({
url: url,
method: 'GET',
data : data
}).done(data => {
// code
}).fail(err => {
// code
})
不吹不黑,jQuery 提供的這一套 Ajax 工具方法真的非常優(yōu)秀,并且經(jīng)歷了這么多年的打磨,其穩(wěn)定性、成熟度自然不必多言。關(guān)于 jQuery 的 Ajax 工具方法的優(yōu)點(diǎn),在前面章節(jié)已經(jīng)講過。至少從使用體驗上來講,簡單易用,功能齊全,以至于我身邊至今依然有很多開發(fā)者在使用這一套工具函數(shù)。
然而,隨著技術(shù)的發(fā)展,jQuery
也逐步走向一個衰弱的過程。越來越多的前端開發(fā)者開始使用諸如 Angular
、React
和 Vue
這樣的新型框架。想像一下,如果我們在一個基本用不到 jQuery 的技術(shù)中進(jìn)行前端開發(fā),為了要使用 jQuery 的 Ajax 相關(guān)方法而強(qiáng)行引入整個 jQuery,這顯然是不現(xiàn)實也不可取的。在更新的技術(shù)中,我們將尋求體積更小,更為先進(jìn)的類庫。
2.fetch
fetch
面世以來,一直都被稱為是 Ajax 的替代方案。作為一個底層的 API 而言,我們將它和 XMLHttpRequest 來進(jìn)行比較。
相信使用過 XMLHttpRequst 的同學(xué),在驚嘆它賦予的前后端交互方式的同時,也無不會詬病它丑陋的代碼組織方式。
舉個例子來說明,假設(shè)我們要往后端發(fā)送一段 GET
請求,使用 XMLHttpRequest 我們會這樣做:
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.responseType = 'text';
xhr.onreadystatechange = function() {
if (this.readyState == 4) {
if (this.status === 200 || this.status === 304) {
// code ...
}
}
};
xhr.onerror = function() {
console.log("Oops, error");
};
xhr.send();
這代碼的組織簡直是丑陋,寫起來也非常的麻煩、松散。
而 fetch 在這方面的表現(xiàn)就不一樣了。Fetch API
是基于 promise
進(jìn)行設(shè)計的,寫法上也更加的方便和簡單,更為符合關(guān)注點(diǎn)分離的原則,不會將所有的配置和狀態(tài)混淆在一個對象里。 接下來我們來看看使用 fetch
的寫法:
// 寫法一:
fetch(url)
.then(response => {
if (response.ok) {
return response.json();
}
})
.then(data => {// code...})
.catch(err => {// code...})
// 寫法二:
const fetchSend = async (url) => {
try {
const response = await fetch(url);
if (response.ok) {
return response.json()
}
} catch(e) {
// code ...
}
}
fetchSend(url)
感覺瞬間優(yōu)雅了許多有木有!使用 promise 寫法,我們的整個代碼組織變得更加整潔有條理性。而方法二使用 async/await
結(jié)合 fetch 的編碼形式,讓我們能夠以同步的方式來書寫代碼,體驗更佳。總結(jié)起來:
- 代碼組織簡單干凈,更具語義性。
- 可以結(jié)合 async/await 書寫,體驗更佳。
然而,fetch 在其他方面表現(xiàn)并不是都很完美。比如:
- 原生支持率不佳,兼容性差。
- 只對網(wǎng)絡(luò)請求報錯,對于諸如 400 和 500 之類的錯誤,并不會走 reject 分支。
- 不支持 abort 和 超時控制。
- 無法檢測請求進(jìn)度。
不得不說, fetch 還需要多多努力呀。
3.axios
接下來講一下大名鼎鼎的 axios
。在 Vue 2.0
之后,著名的 Vue 作者尤雨溪曾推薦過,而我對 axios 的認(rèn)識也開始于此。
axios 在瀏覽器端實際上也是基于 XMLHttpRequest 來實現(xiàn)的,并且基于 promise 提供了一套 promise 風(fēng)格的鏈?zhǔn)秸{(diào)用 API。在展示代碼書寫風(fēng)格之前,我忍不住要說幾個 axios 的亮點(diǎn):
- 支持 promise API。
- 支持請求和響應(yīng)攔截。
- 提供并發(fā)請求接口功能。
- 輕量高效、簡單易用。
- 客戶端支持防止CSRF。
- 支持 node 端。
可以說,axios 的設(shè)計非常的全面和優(yōu)秀,甚至還支持 node 端,而支持?jǐn)r截請求和響應(yīng)、支持并發(fā)請求接口更是滿足了很多業(yè)務(wù)場景的需求。接下來看看 axios 一般書寫方式:
// 簡單的請求
axios.get(url, {
params: params
}).then(function (response) {
// code ...
}).catch(function (error) {
console.log(error);
})
// 并發(fā)請求
function axios1() {
return axios.get(url);
}
function axios2() {
return axios.get(url);
}
axios.all([axios1(), axios2()])
.then(axios.spread(function (acct, perms) {
// code ...
}));
顯而易見,簡單、高效,并且 API 體驗非常好。事實上,我也更加推薦大家在實際工作中使用 axios 。而關(guān)于如何學(xué)習(xí) axios ,除了官方文檔和各類博客之外,這里我也推薦慕課網(wǎng)的一門課程 TypeScript 從零重構(gòu) Axios,有興趣一邊學(xué)習(xí) axios 原理實現(xiàn),一邊造輪子的同學(xué),都可以看看。
4.結(jié)尾
一路走來,前端發(fā)展的過程中誕生了很多優(yōu)秀的前后端交互的技術(shù)。本章從 jQuery Ajax
、fetch
和 axios
三者展開討論和比較,盡管 jQuery 對于現(xiàn)在來講比較老舊了,但這絲毫不妨礙它是一個優(yōu)秀的類庫,它提供的 Ajax 功能也確實是非常好。而 fetch 后來的替代方案,本身的設(shè)計也是可圈可點(diǎn)的,只是現(xiàn)在來講還過于稚嫩,不適用于我們業(yè)務(wù)中推廣使用。相比之下,axios 可算是當(dāng)打之年,從設(shè)計上、從體積上,都很適用于我們現(xiàn)在的各種前端技術(shù)體系中,因此,我也推薦同學(xué)們可以進(jìn)一步的學(xué)習(xí)和使用這個技術(shù)。