XMLHttpRequest與Fetch API
本文最初發布于 OpenReplay 博客,由 InfoQ 中文站翻譯并分享。
Ajax 是大多數 web 應用程序背后的核心技術,它允許頁面向 web 服務發出異步請求,因此數據可以不經過頁面往返服務器無刷新顯示數據。
術語 Ajax 不是一種技術,相反,它指的是從客戶端腳本加載服務器數據的方法。多年來已經引入了幾種選擇,目前有兩種主要方法,大多數 JavaScript 框架使用其中一種或兩種。
在本文中,我們將研究早期 XMLHttpRequest 和現代 Fetch 的優缺點,以確定哪種 Ajax API 最適合你的應用。
XMLHttpRequest
XMLHttpRequest 在 1999 年首次作為非標準的 Internet Explorer 5.0 ActiveX 組件出現,微軟開發它是為了支持基于瀏覽器的 Outlook 版本,XML 是當時最流行(或被宣揚)的數據格式,除此之外,XMLHttpRequest 還支持文本和尚未發明的 JSON。
Jesse James Garrett 在他 2005 年的文章《AJAX: Web 應用程序的新方法》中提出了“AJAX”概念,那時谷歌郵箱和谷歌地圖等基于 AJAX 的應用程序已經存在,但是這個術語激勵了開發人員,并引起了流暢的 Web 2.0 體驗爆炸式增長。
AJAX 是“Asynchronous JavaScript and XML”的縮寫,盡管嚴格地說,開發人員并不需要使用異步方法、JavaScript 或 XML。我們現在將通用的“Ajax”術語表示任何從服務器獲取數據、更新 DOM 而無需刷新整個頁面的客戶端過程。
所有主流瀏覽器都支持 XMLHttpRequest,并在 2006 年成為官方的 web 標準。下面是一個簡單的例子,從你的域 / 服務 / 端點獲取數據,然后在控制臺將 JSON 結果顯示為文本:
onreadystatechange 回調函數在請求的生命周期中運行好幾次;XMLHttpRequest 對象的 readyState 屬性則返回當前狀態:
0 (uninitialized) - 請求未初始化
1(loading)- 服務器連接建立
2(loaded)- 請求收到
3(interactive)- 處理請求
4(complete)- 請求完成,響應準備就緒
在達到狀態 4 之前,幾個函數就可以做很多事情。
Fetch
Fetch 是一個現代基于 promise 的 Ajax 請求 API,首次出現于 2015 年,在大多數瀏覽器中都得到了支持。它不是基于 XMLHttpRequest 構建的,并且用更簡潔的語法提供了更好的一致性。下面的 Promise 鏈函數與上面的 XMLHttpRequest 例子相同:
或者你可以使用 async/await:
Fetch 更清晰、更簡潔,并且經常在 Service worker 中使用。
開源會話重播
OpenReplay 是 FullStory 和 LogRocket 的開源替代品,它通過回放用戶在你的應用程序上的一切操作,并顯示每個問題的操作堆棧,提供完整的可觀察性。OpenReplay 是自托管的,可以完全控制你的數據。
快樂調試吧!現代的前端團隊 —— 開始自由地監控你的 web 應用程序。
第 1 回合:Fetch 獲勝
與陳舊的 XMLHttpRequest 相比,Fetch API 除了具有更清晰簡潔的語法之外,還有其它幾個優勢。
頭、請求和響應對象
上面簡單 fetch() 示例中,使用一個字符串定義 URL 端點,也可以傳遞一個可配置的 Request 對象,它提供了有關調用的一系列屬性:
Response 對象提供了對訪問所有詳細信息的類似訪問:
Headers 對象提供了一個簡單的接口來設置請求中的頭信息或獲取響應中的頭信息:
緩存控制
在 XMLHttpRequest 中管理緩存具有挑戰性,你可能會發現有必要附加一個隨機查詢字符串值來繞過瀏覽器緩存,Fetch 方法在第二個參數 init 對象中內置了對緩存的支持:
緩存可以設置為:
'default' —— 如果有一個新的 (未過期的) 匹配,則使用瀏覽器緩存;如果沒有,瀏覽器會發出一個帶條件的請求來檢查資源是否已改變,并在必要時會發出新的請求
'no-store' —— 繞過瀏覽器緩存,并且網絡響應不會更新它
'reload' —— 繞過瀏覽器緩存,但是網絡響應會更新它
'no-cache' —— 類似于'default',除了一個條件請求總是被做
'force-cache' —— 如果可能,使用緩存的版本,即使它過時了
'only-if-cached' —— 相同的 force-cache,除了沒有網絡請求
跨域控制
跨域共享資源允許客戶端腳本向另一個域發出 Ajax 請求,前提是該服務器允許 Access-Control-Allow-Origin 響應頭中的源域;如果沒有設置這個參數, fetch() 和 XMLHttpRequest 都會失敗。但是,Fetch 提供了一個模式屬性,可以在第二個參數的 init 對象中設置‘no-cors’屬性。
這將返回一個不能讀取但可以被其它的 API 使用的響應。例如,你可以使用 Cache API 存儲返回再之后使用,可能從 Service Worker 返回一個圖像、腳本或 CSS 文件。
憑證控制
XMLHttpRequest 總是發送瀏覽器 cookie,Fetch API 不會發送 cookie,除非你顯式地在第二個參數 init 對象中設置 credentials 屬性。
credentials 可以設置為:
'omit' —— 排除 cookie 和 HTTP 認證項 (默認)
'same-origin' —— 包含對同源 url 的請求的憑證
'include' —— 包含所有請求的憑證
請注意,include 是早期 API 實現中的默認值,如果你的用戶可能運行舊的瀏覽器,就得顯式地設置 credentials 屬性。
重定向控制
默認情況下,fetch() 和 XMLHttpRequest 都遵循服務器重定向。但是,fetch() 在第二個參數 init 對象中提供了替代選項:
redirect 可以設置為:
'follow' —— 遵循所有重定向(默認)
'error' —— 發生重定向時中止(拒絕)
'manual' —— 返回手動處理的響應
數據流
XMLHttpRequest 將整個響應讀入內存緩沖區,但是 fetch() 可以流式傳輸請求和響應數據,這是一項新技術,流允許你在發送或接收時處理更小的數據塊。例如,你可以在完全下載前處理數兆字節文件中的信息,下面的示例將傳入的(二進制)數據塊轉換為文本,并將其輸出到控制臺。在較慢的連接上,你會看到更小的數據塊在較長的時間內到達。
服務器端支持
Deno 和 Node 18 中完全支持 Fetch,在服務器和客戶端使用相同的 API 有助于減少認知成本,還提供了在任何地方運行的同構 JavaScript 庫的可能性。
第二輪:XMLHttpRequest 獲勝
盡管存在缺陷,XMLHttpRequest 還是有一些技巧可以超越 ajax Fetch()。
進度支持
我們可以監控請求的進度,通過將一個處理程序附加到 XMLHttpRequest 對象的進度事件上。這在上傳大文件(如照片)時特別有用:
事件處理程序傳遞的對象有三個屬性:
lengthComputable —— 如果進度可以計算,則設置為 true
total —— 消息體的工作總量或內容長度
loaded —— 到目前為止完成的工作或內容的數量
Fetch API 沒有提供任何方法來監控上傳進度。
超時支持
XMLHttpRequest 對象提供了一個 timeout 屬性,可以將其設置為請求自動終止前允許運行的毫秒數;如果超時,就觸發一個 timeout 事件來處理:
fetch() 中可以封裝一個函數來實現超時功能:
或者,你可以使用 Promise.race():
這兩個方法都不容易使用,另外請求將在后臺繼續運行。
中止支持
運行中的請求可以通過 XMLHttpRequest 的 abort() 方法取消,如有必要,可以附加一個 abort 事件來處理:
你可以中止一個 fetch(),但它不是那么直接,需要一個 AbortController 對象:
當 fetch() 中止時,catch() 塊執行。
更顯式的故障檢測
當開發人員第一次使用 fetch() 時,假設一個 HTTP 錯誤,如 404 Not Found 或 500 Internal Server error 將觸發 Promise 拒絕并運行相關的 catch() 塊,這似乎是合乎邏輯的,但事實并非如此:Promise 成功地解決了這些響應,只有當網絡沒有響應或請求被中斷時,才會發生拒絕。
fetch() 的 Response 對象提供了 status 和 ok 屬性,但并不總是顯式地需要檢查它們,XMLHttpRequest 更明確,因為單個回調函數處理每一個結果:你應該在每個示例中都看到 stuatus 檢查。
瀏覽器支持
我希望你不必支持 Internet Explorer 或 2015 年之前的瀏覽器版本,但如果是這樣的話,XMLHttpRequest 是你唯一的選擇。XMLHttpRequest 也很穩定的,API 不太可能更新。Fetch 比較新,還缺少幾個關鍵特性,雖然更新不太可能破壞代碼,但你可以期待一些維護。
應該使用哪個 API ?
大多數開發人員都會使用更新的 Fetch API,它的語法更簡潔,比 XMLHttpRequest 更有優勢;也就是說,這些好處中的許多都有特定的用例,但在大多數應用程序中都不需要它們。只有兩種情況下 XMLHttpRequest 仍必不可少:
你正在支持非常老的瀏覽器——這種需求會隨著時間的推移而下降。
你需要顯示上傳進度條。Fetch 后續將會支持,但可能需要幾年的時間。
這兩種選擇都很有趣,值得詳細了解它們!
轉載請在文章開頭和結尾顯眼處標注:作者、出處和鏈接。不按規范轉載侵權必究。
未經授權嚴禁轉載,授權事宜請聯系作者本人,侵權必究。
本文禁止轉載,侵權必究。
授權事宜請至數英微信公眾號(ID: digitaling) 后臺授權,侵權必究。
評論
評論
推薦評論
暫無評論哦,快來評論一下吧!
全部評論(0條)