您當前的位置:首頁 > 歷史

使用更優雅的非同步請求API——fetch

作者:由 張墨吟 發表于 歷史時間:2016-12-12

如果你還不知道fetch是什麼,那至少你應該知道XMLHttpRequest,我們接下來就從XMLHttpRequest講起。

XMLHttpRequest是一個Javascript物件,用於在後臺與伺服器交換資料。它最初由微軟設計,隨後被廣泛採納。 如今,該物件已經被 W3C 組織標準化,受到了所有現代瀏覽器的支援。

當我們想要使用XMLHttpRequest傳送一個請求時,通常這樣來做:

首先建立一個 XMLHttpRequest 例項:

var xmlhttp = new XMLHttpRequest()

之後使用open方法初始化一個請求:

let url = location。herf;

xmlhttp。open(‘get’, url, true);

定義回撥函式,只要XMLHttpRequest。readyState 屬性發生變化,就會觸發readystatechange事件,同時有一個事件處理回撥函式被執行:

xmlhttp。onreadystatechange = function () {

if(xmlhttp。readyState === XMLHttpRequest。DONE && xmlhttp。status === 200) console。log(xmlhttp。responseText);

};

最後傳送請求:

xmlhttp。send();

這樣就完成了一個基本的獲取資源的請求。 完整的指令碼如下,開啟瀏覽器除錯工具,執行這段指令碼的話,你會看到獲取到的頁面原始碼。

var url = location。herf;

xmlhttp。open(‘get’, url, true);

xmlhttp。onreadystatechange = function () {

if(xmlhttp。readyState === XMLHttpRequest。DONE && xmlhttp。status === 200) console。log(xmlhttp。responseText);

};

xmlhttp。send();

可能對於一些剛入門的人來說,關於 XMLHttpRequest 的使用方法也並不熟悉,畢竟很多人和我一樣相較於原生js,jQuery寫的要更多些。所以我們也可以先回顧下 jQuery 的 ajax 介面。

在 ajax 中, 我們傳送一條請求時通常這樣來寫:

$。ajax({

type: ‘get’,

url: location。herf,

success: function(data){

console。log(data);

}

})

我們的知乎也使用了jQuery,複製這段程式碼貼到控制檯執行後,也可以看到打印出來的頁面原始碼。

到這裡我們已經使用 XMLHttpRequest 與 ajax 實現獲取非同步資源了。那麼,如果使用 fetch API 的話,這個步驟會是怎樣的呢?

其實很簡單,只需要像下面這樣:

fetch(location。herf, {

method: “get”

})。then(function(response) {

return response。text()

})。then(function(body) {

console。log(body)

})

在你的瀏覽器中執行此段指令碼,同樣會打印出本頁原始碼。我們使用了這段程式碼實現了和上面 XMLHttpRequset 與 ajax 示例指令碼相同的功能。

那麼我們回過頭來,仔細看一下這段fetch指令碼:

首先是 fetch() 方法。

fetch(input, init)

這個方法接受兩個引數:

input

定義要獲取的資源。可以是一個 USVString 字串,包含要獲取資源的 URL。 也可以是一個 Request 物件。

init

這個引數是可選的,它傳入一個配置項物件,可以用它來包括所對請求進行設定。

簡單地說,input 引數就相當於我們使用 ajax 時傳入的url。 那 ajax 的 type 引數在哪裡配置呢?答案當然是在另一個引數 init 裡。 init可以配置其他請求相關引數,包括:

method: 請求使用的方法,如 GET、POST。

headers: 請求的頭資訊,形式為 Headers 物件或 ByteString。

body: 請求的 body 資訊,可能是一個 Blob、BufferSource、FormData、URLSearchParams 或者 USVString 物件。(如果是 GET 或 HEAD 方法,則不能包含 body 資訊)

mode: 請求的模式,如 cors、 no-cors 或者 same-origin。

credentials: 請求的 credentials,如 omit、same-origin 或者 include。

cache: 請求的 cache 模式: default, no-store, reload, no-cache, force-cache, or only-if-cached。

現在我們配置好了請求,可是還有回撥函式呢?ajax 有 success 欄位,XMLHttpRequest 有 onstatechange 方法,fetch為我們實現了什麼?

從上面的 fetch 例項中,顯而易見的,他的回撥是在 then 中執行的。

說到這裡,我們不得不提一個 es6 中新引入的概念: Promise。

ES6的Promise物件是一個建構函式,用來生成Promise例項。下面是Promise物件的基本用法。

var promise = new Promise(function(resolve, reject) {

if (/* 非同步操作成功 */){

resolve(value);

} else {

reject(error);

}

});

promise。then(function(value) {

// success

}, function(value) {

// failure

});

上面程式碼中,Promise建構函式接受一個函式作為引數,該函式的兩個引數分別是resolve方法和reject方法。如果非同步操作成功,則用resolve方法將Promise物件的狀態變為“成功”(即從pending變為resolved);如果非同步操作失敗,則用reject方法將狀態變為“失敗”(即從pending變為rejected)。

Promise物件使用then方法添加回調函式。then方法可以接受兩個回撥函式,第一個是非同步操作成功時(變為resolved狀態)時的回撥函式,第二個是非同步操作失敗(變為rejected)時的回撥函式(可以省略)。一旦狀態改變,就呼叫相應的回撥函式。

瞭解了以上內容基本上就能解決我們關於 fetch 使用的疑惑了,想要深入瞭解 Promise 的話可以看這裡。

回到我們的fetch。fetch 方法返回的便是為一個 Promise,resolve 時回傳 Response 物件。因此,我們可以用promise的 then 方法直接以鏈式操作的形式來設定 fetch 回撥。

使用形式如下:

fetch(input, init)。then(function(response) { /*請求成功回撥*/ });`

到這裡我們對 fetch 有了一個大致的瞭解, 你可能已經迫不及待想要試一試了。但是,一個不幸的訊息是,目前各主流瀏覽器對 fetch 的支援情況不是很好。

使用更優雅的非同步請求API——fetch

使用更優雅的非同步請求API——fetch

不過,我們可以使用Fetch Polyfil來實現 fetch 功能。

關於fetch polyfil的使用方法github上有詳細介紹,為了方便大家瞭解,我在這裡簡單講述一下。

以下使用方法基於node環境及ES2015:

安裝:

npm install whatwg-fetch ——save

如果你的瀏覽器版本太低,不支援Promise,那你還需要安裝:

npm install promise-polyfill ——save-exact

或者

npm install core-js ——save

在檔案中引入:

import ‘whatwg-fetch’;

import Promise from ‘promise-polyfill’;

或者

import ‘whatwg-fetch’;

import ‘core-js/es6/promise’;

到這裡就可以正常的使用 fetch API 了。

這裡檢視更多關於 fetch API 的資訊

最後,如果想使用 fetch 傳送 jsonp 格式請求,這裡有一個庫 fetch-jsonp

只需要在fetch的基礎上安裝fetch-jsonp 然後在檔案中引入就可以正常使用了:

npm install fetch-jsonp

import fetchJsonp from ‘fetch-jsonp’;

fetchJsonp(‘/users。jsonp’)

。then(function(response) {

return response。json()

})。then(function(json) {

console。log(‘parsed json’, json)

})。catch(function(ex) {

console。log(‘parsing failed’, ex)

})

從現在開始,愉快的使用fetch API 吧~