前言:
最近在研究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。
我是在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'