話說Fetch這個API


前言:

最近在研究React這個框架,成功的成為了一名新的入坑着。用過React的都知道React的強大主要是在於它的生態的強大,React說的再大不過也就是一個UI框架罷了。不過我們學習react也主要因為這個生態,有facebook支持,質量相對有保障,衍生出的react-native, react-canvas等輪子在很多場景下可以直接拿來用。碎片化是React當前的狀態,比如flux庫,promise庫,utils函數庫,dom操作庫,ajax庫等等,每個點都有2-3個庫在開源社區處於競爭狀態,各有所長,大家根據自身的需要去選擇。而我打算用Fetch作為ajax庫來擺脫jquery這個千年不變的大殺器。

Fetch介紹

我們一提到局部刷新,前后端交互,異步加載等首先想到的ajax,好像在我們的認知中除了ajax就沒有別的了。其實我們都被這種觀念誤導了,ajax只是對於XMLHttpRequest的一種封裝,我們談及Ajax技術的時候,通常意思就是基於XMLHttpRequest的Ajax,它是一種能夠有效改進頁面通信的技術。而Fetch API則是XMLHttpRequest的最新替代技術, 它是W3C的正式標准。

Fetch的使用

下面我們看一下Fetch的兼容性

Fetch的兼容性

總體來說,最新的瀏覽器都開始慢慢的兼容它了,但是想讓它獨立的用於前端項目還是任重而道遠啊。。。

如果你想獨立在前端項目中兼容Fetch,可以考慮看這篇文章使用fetch遇到過的坑但是我不推薦去自己部署Fetch。

我是在React項目中了解到Fetch的,使用的包是:whatwg-fetch

Fetch的優點

前面說了那么多,身為吃瓜群眾的我們就是好奇:那他有什么優點能讓顛覆了整個前端行業的ajax退位讓賢呢?

XMLHttpRequest 是一個設計粗糙的 API,不符合關注分離(Separation of Concerns)的原則,配置和調用方式非常混亂,而且基於事件的異步模型寫起來也沒有現代的 Promise,generator/yield,async/await 友好。

Fetch 的出現就是為了解決 XHR 的問題,拿例子說明:

使用 XHR 發送一個 json 請求一般是這樣:

var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.responseType = 'json';

xhr.onload = function() {
  console.log(xhr.response);
};

xhr.onerror = function() {
  console.log("Oops, error");
};

xhr.send();

使用 Fetch 后,頓時看起來好一點(其實jquery的ajax也實現了Promise)

fetch(url).then(function(response) {
  return response.json();
}).then(function(data) {
  console.log(data);
}).catch(function(e) {
  console.log("Oops, error");
});

使用 ES6 的 箭頭函數 后:

fetch(url).then(response => response.json())
  .then(data => console.log(data))
  .catch(e => console.log("Oops, error", e))

現在看起來好很多了,但這種 Promise 的寫法還是有 Callback 的影子,而且 promise 使用 catch 方法來進行錯誤處理的方式有點奇怪。不用急,下面使用 async/await 來做最終優化:

注:async/await 是非常新的 API,屬於 ES7,目前尚在 Stage 1(提議) 階段,這是它的完整規范。使用 Babel 開啟 runtime 模式后可以把 async/await 無痛編譯成 ES5 代碼。也可以直接使用 regenerator 來編譯到 ES5。

try {
  let response = await fetch(url);
  let data = await response.json();
  console.log(data);
} catch(e) {
  console.log("Oops, error", e);
}
// 注:這段代碼如果想運行,外面需要包一個 async function

duang~ 的一聲,使用 await 后,寫異步代碼就像寫同步代碼一樣爽。await 后面可以跟 Promise 對象,表示等待 Promise resolve() 才會繼續向下執行,如果 Promise 被 reject() 或拋出異常則會被外面的 try...catch 捕獲。

Promise,generator/yield,await/async 都是現在和未來 JS 解決異步的標准做法,可以完美搭配使用。這也是使用標准 Promise 一大好處。最近也把項目中使用第三方 Promise 庫的代碼全部轉成標准 Promise,為以后全面
使用 async/await 做准備。

以上資料來自 傳統 Ajax 已死,Fetch 永生

但是我認為Fetch最不同於ajax的是讓我們對於請求頭的設置更加方便,更加靈活。

Fetch中的API

對於傳統的XMLHttpRequest而言,你必須使用它的一個實例來執行請求和檢索返回的響應。 但是通過Fetch API,我們還能夠明確的配置請求對象。你可以通過Request構造器函數創建一個新的請求對象,這也是建議標准的一部分。 第一個參數是請求的URL,第二個參數是一個選項對象,用於配置請求。請求對象一旦創建了, 你便可以將所創建 的對象傳遞給fetch()方法,用於替代默認的URL字符串。示例代碼如下:

var req = new Request(URL, {method: 'GET', cache: 'reload'});
fetch(req).then(function(response) {
  return response.json();
}).then(function(json) {
  insertPhotos(json);
});

上面的代碼中我們指明了請求使用的方法為GET,並且指定不緩存響應的結果。

有關Request對象的另一件更酷的事在於,你還可以基於原有的對象創建一個新的對象。 新的請求和舊的並沒有什么不同,但你可以通過稍微調整配置對象,將其用於不同的場景。 例如,你可以基於原有的GET請求創建一個POST請求,它們具有相同的請求源。代碼如下:


 // 基於req對象創建新的postReq對象
  var postReq = new Request(req, {method: 'POST'});

每個Request對象都有一個header屬性,在Fetch API中它對應了一個Headers對象。 通過Headers對象,你能夠修改請求頭。不僅如此,對於返回的響應,你還能輕松的返回響應頭中的各個屬性。 但是需要注意的是,響應頭是只讀的。

var headers = new Headers();
headers.append('Accept', 'application/json');
var request = new Request(URL, {headers: headers});

fetch(request).then(function(response) {
    console.log(response.headers);
});

在上面的代碼中,你可以通過Headers構造器來獲取這個對象,用於為新的Request對象配置請求頭。

相似的,你可以創建一個Response對象:

function responseDemo() {
    var headers = new Headers({
        'Content-Type': 'application/json',
        'Cache-Control': 'max-age=3600'
    });

    var response = new Response(
        JSON.stringify({photos: {photo: []}}),
            {status: 200, headers: headers}
    );
    response.json().then(function(json) {
        insertPhotos(json);
    });
}

Request和Response都完全遵循HTTP標准。
以上資料來自 深入淺出Fetch API

最后再說點

其實整合這篇文章毛目的沒有,就是因為注意用post提交數據時記得設置'Content-Type'為'application/x-www-form-urlencoded; charset=UTF-8'


免責聲明!

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



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