了解 Fetch API與Fetch+Async/await


背景

提及前端與服務器端的異步通信,離不開 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 規范明確了用戶代理獲取資源的語義。原生支持 Promise1,調用方便,符合語義化。可配合使用 ES2016 中的 asyncawait 語法,更加優雅。

通過一個例子來快速了解和使用 Fetch API 最基本的用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 獲取 some.json 資源
fetch('some.json')
.then(function(response) {
return response.json();
})
.then(function(data) {
console.log('data', data);
})
.catch(function(error) {
console.log('Fetch Error: ', error);
});

// 采用ES2016的 async/await 語法
async function() {
try {
const response = await fetch('some.json');
const data = response.json();
console.log('data', data);
} catch (error) {
console.log('Fetch Error: ', error)
}
}

通過例子我們可以發現,使用 Fetch API 能夠快速便捷地進行資源地獲取。

可以簡單理解為,Fetch API 是面向未來的異步通信 API。

具體用法

fetch 方法

fetch 方法有兩種調用方式。

1
2
Promise fetch(String url, [, Object options])
Promise fetch(Request req, [, Object options])
  1. 第一個參數是一個 Request 對象,第二個參數是配置信息,可選
  2. 第一個參數是一個 url,第二個參數是配置信息,可選

可選配置信息是一個 Object 對象,可以包含以下字段:

  • method: 請求的方法,例如:GETPOST
  • headers: 請求頭部信息,可以是一個簡單的對象,也可以是 Headers 類實例化的一個對象。
  • body: 需要發送的信息內容,可以是 BlobBufferSourceFormDataURLSearchParams 或者 USVString。注意,GETHEAD方法不能包含body。
  • mode: 請求模式,分別有 corsno-corssame-originnavigate 這幾個可選值。
    • cors: 允許跨域,要求響應中 Acess-Control-Allow-Origin 這樣的頭部表示允許跨域。
    • no-cors: 只允許使用 HEADGETPOST方法。
    • same-origin: 只允許同源請求,否則直接報錯。
    • navigate: 支持頁面導航。
  • credentials: 表示是否發送cookie,有三個選項
    • omit: 不發送cookie
    • same-origin: 僅在同源時發送cookie
    • include: 發送cookie
  • cache: 表示處理緩存的策略。
  • redirect: 表示發生重定向時,有三個選項
    • follow: 跟隨。
    • error: 發生錯誤。
    • manual: 需要用戶手動跟隨。
  • integrity: 包含一個用於驗證資資源完整性的字符串。

Headers

Headers 可用來表示 HTTP 的頭部信息,使用 Headers 的接口,你可以通過 Headers() 構造函數來創建一個你自己的 headers對象。

1
2
3
4
5
6
7
8
var headers = new Headers({
"Content-Type": "text/plain",
"Content-Length": content.length.toString(),
"X-Custom-Header": "ProcessThisImmediately",
});
headers.append("X-Custom-Header", "AnotherValue");
headers.has("Content-Type") // true
headers.getAll("X-Custom-Header"); // ["ProcessThisImmediately", "AnotherValue"]

Headers 提供 appenddeletegetgetAllhassetforEach等這些實例方法,可供開發者更加靈活地配置請求中的 headers。

Request

Request 類用於描述請求內容。構造函數接受的參數與fetch方法一致,這里就不展開介紹了。我們可以這么理解,事實上fetch方法在調用時,會將傳入的參數構造出一個 Request 對象並執行。

1
2
3
4
5
6
7
var URL = '//api.some.com';
var getReq = new Request(URL, {method: 'GET', cache: 'reload'});
fetch(getReq).then(function(response) {
return response.json();
}).catch(function(error) {
console.log('Fetch Error: ', error);
});

Request 接口中的配置項 headers 可以是實例化的 Headers 。

1
2
3
4
5
6
7
8
9
10
11
12
13
var URL = '//api.some.com';
// 實例化 Headers
var headers = new Headers({
"Content-Type": "text/plain",
"Content-Length": content.length.toString(),
"X-Custom-Header": "ProcessThisImmediately",
});
var getReq = new Request(URL, {method: 'GET', headers: headers });
fetch(getReq).then(function(response) {
return response.json();
}).catch(function(error) {
console.log('Fetch Error: ', error);
});

更便捷的是,Request 對象可以從已有的 Request 對象中繼承,並拓展新的配置。

1
2
3
4
var URL = '//api.some.com';
var getReq = new Request(URL, {method: 'GET', headers: headers });
// 基於已存在的 Request 實例,拓展創建新的 Request 實例
var postReq = new Request(getReq, {method: 'POST'});

Response

Response 實例是在fentch()處理完promises之后返回的。它的實例也可用通過JavaScript來創建,但只有在ServiceWorkers中才真正有用。

1
var res = new Response(body, init);

其中 body 可以是 BolbBufferSourceFormDataURLSearchParamsUSVString 這些類型的值。

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 。

瀏覽器支持

image

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。

參考文檔

 

 

 

 

 

.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM