背景
提及前端與服務器端的異步通信,離不開 Ajax (Asynchronous JavaScript and XML)。實際上我們常說的 Ajax 並非指某一項具體的技術,它主要是基於用腳本操作 HTTP 請求的 Web 應用架構。最早出現在 Jesse James Carrett 於 2005年2月發表一篇《Ajax:A New Approach to Web Applications》中提出的一個新概念。
在 Ajax 中涉及到的 JavaScript 方面的技術,即 XMLHttpRequest(以下簡稱 XHR)。很長一段時間我們都是通過 XHR 來與服務器建立異步通信。然而在使用的過程中,我們發現 XHR 是基於事件的異步模型,在設計上將輸入、輸出和事件監聽混雜在一個對象里,且必須通過實例化方式來發請求。配置和調用方式混亂,不符合關注分點離原則。
關注點分離原則所描述的是系統的元素應該表現出互不相干的目的。也就是說,沒有會分擔另外一個元素職責的,或者其它不相干職責的元素。
正是由於 XHR 在使用上的不便,許多前端庫就將進行封裝,方便開發者調用。其中影響和使用范圍最廣的當屬 jQuery 提供的 $.ajax
方法。該方法最為先進之處在於,從 jQuery 1.5 開始,$.ajax()
返回的jqXHR對象 實現了 Promise 接口, 使它擁有了 Promise 的所有屬性,方法和行為。
直到 Fetch API 的提出,前端和服務器端的異步通信方面更進了一步。
技術介紹
Fetch API 是近年來被提及將要取代 XHR
的技術新標准,是一個 HTML5 的 API。
Fetch 並不是 XHR
的升級版本,而是從一個全新的角度來思考的一種設計。Fetch 是基於 Promise 語法結構,而且它的設計足夠低階,這表示它可以在實際需求中進行更多的彈性設計。對於 XHR 所提供的能力來說,Fetch 已經足夠取代 XHR
,並且提供了更多拓展的可能性。
快速了解
Fetch API 規范明確了用戶代理獲取資源的語義。原生支持 Promise
1,調用方便,符合語義化。可配合使用 ES2016 中的 async
/ await
語法,更加優雅。
通過一個例子來快速了解和使用 Fetch API 最基本的用法
1 |
// 獲取 some.json 資源 |
通過例子我們可以發現,使用 Fetch API 能夠快速便捷地進行資源地獲取。
可以簡單理解為,Fetch API 是面向未來的異步通信 API。
具體用法
fetch 方法
fetch 方法有兩種調用方式。
1 |
Promise fetch(String url, [, Object options]) |
- 第一個參數是一個
Request
對象,第二個參數是配置信息,可選 - 第一個參數是一個
url
,第二個參數是配置信息,可選
可選配置信息是一個 Object 對象,可以包含以下字段:
- method: 請求的方法,例如:
GET
,POST
。 - headers: 請求頭部信息,可以是一個簡單的對象,也可以是 Headers 類實例化的一個對象。
- body: 需要發送的信息內容,可以是
Blob
,BufferSource
,FormData
,URLSearchParams
或者USVString
。注意,GET
,HEAD
方法不能包含body。 - mode: 請求模式,分別有
cors
,no-cors
,same-origin
,navigate
這幾個可選值。- cors: 允許跨域,要求響應中
Acess-Control-Allow-Origin
這樣的頭部表示允許跨域。 - no-cors: 只允許使用
HEAD
,GET
,POST
方法。 - same-origin: 只允許同源請求,否則直接報錯。
- navigate: 支持頁面導航。
- cors: 允許跨域,要求響應中
- credentials: 表示是否發送
cookie
,有三個選項- omit: 不發送
cookie
。 - same-origin: 僅在同源時發送
cookie
。 - include: 發送
cookie
。
- omit: 不發送
- cache: 表示處理緩存的策略。
- redirect: 表示發生重定向時,有三個選項
- follow: 跟隨。
- error: 發生錯誤。
- manual: 需要用戶手動跟隨。
- integrity: 包含一個用於驗證資資源完整性的字符串。
Headers
Headers
可用來表示 HTTP 的頭部信息,使用 Headers
的接口,你可以通過 Headers() 構造函數來創建一個你自己的 headers
對象。
1 |
var headers = new Headers({ |
Headers
提供 append
, delete
, get
, getAll
, has
, set
, forEach
等這些實例方法,可供開發者更加靈活地配置請求中的 headers。
Request
Request
類用於描述請求內容。構造函數接受的參數與fetch方法一致,這里就不展開介紹了。我們可以這么理解,事實上fetch方法在調用時,會將傳入的參數構造出一個 Request 對象並執行。
1 |
var URL = '//api.some.com'; |
Request 接口中的配置項 headers 可以是實例化的 Headers 。
1 |
var URL = '//api.some.com'; |
更便捷的是,Request 對象可以從已有的 Request 對象中繼承,並拓展新的配置。
1 |
var URL = '//api.some.com'; |
Response
Response 實例是在fentch()處理完promises之后返回的。它的實例也可用通過JavaScript來創建,但只有在ServiceWorkers中才真正有用。
1 |
var res = new Response(body, init); |
其中 body
可以是 Bolb
, BufferSource
, FormData
, URLSearchParams
, USVString
這些類型的值。
init 是一個對象,可以包括以下這些字段
- status: 響應狀態碼
- statusText: 狀態信息
- headers: 頭部信息,可以是對象或者
Headers
實例
Response
實例提供了以下實例屬性,均是只讀屬性。
- bodyUsed: 用於表示響應內容是否被使用過
- headers: 頭部信息
- ok: 表明請求是否成功,響應狀態為 200 ~ 299 時,值為 true
- status: 狀態碼
- statusText: 狀態信息
- type: 響應類型
- basic: 同源
- cors: 跨域
- error: 出錯
- opaque: Request mode 設置為 “no-cors”的響應
- url: 響應地址
Response
實例提供以下實例方法。
- clone: 復制一個響應對象。
- arrayBuffer: 將響應數據轉換為 arrayBuffer 后 reslove 。
- bolb: 把響應數據轉換為 Bolb 后 reslove 。
- formData: 把響應數據轉換為 formData 后 reslove 。
- json: 把響應內容解析為對象后 reslove 。
- text: 把響應數據當做字符串后 reslove 。
瀏覽器支持
Chrome 45+, Opera 44+,Firefox 51+ 和 IE Edge 等這些版本的瀏覽器開始支持 Fetch API。移動端瀏覽器也在逐步得到支持。
我們可以通過對 window.fetch
的能力檢測,判斷出瀏覽器是否支持 Fetch API。github 官方推出了一個 Fetch API 的 polyfill 庫,可以讓更多瀏覽器提前感受到 Fetch API 的便捷的開發體驗。
結語
雖然 Fecth API 使用方便符合語義化,但是現階段它也有所限制。Fetch API 是基於 Promise,由於 Promise 沒有處理 timeout 的機制,所以無法通過原生方式處理請求超時后的中斷,和讀取進度的能力。但是相信未來為了支持流,Fetch API 最終將會提供可以中斷執行讀取資源的能力,並且提供可以讀取進度的 API。
參考文檔
.