傳統(tǒng) Ajax 已死,F(xiàn)etch 永生

原諒我做一次標題黨料扰,Ajax 不會死凭豪,傳統(tǒng) Ajax 指的是 XMLHttpRequest(XHR),未來現(xiàn)在已被 Fetch 替代晒杈。
最近把阿里一個千萬級 PV 的數(shù)據(jù)產品全部由 jQuery 的 $.ajax
遷移到 Fetch
嫂伞,上線一個多月以來運行非常穩(wěn)定。結果證明拯钻,對于 IE8+ 以上瀏覽器帖努,在生產環(huán)境使用 Fetch 是可行的。
由于 Fetch API 是基于 Promise 設計粪般,有必要先學習一下 Promise拼余,推薦閱讀 MDN Promise 教程。舊瀏覽器不支持 Promise亩歹,需要使用 polyfill es6-promise 匙监。
本文不是 Fetch API 科普貼,其實是講異步處理和 Promise 的小作。Fetch API 很簡單亭姥,看文檔很快就學會了。推薦 MDN Fetch 教程 和 萬能的WHATWG Fetch 規(guī)范

Why Fetch
XMLHttpRequest 是一個設計粗糙的 API顾稀,不符合關注分離(Separation of Concerns)的原則达罗,配置和調用方式非常混亂础拨,而且基于事件的異步模型寫起來也沒有現(xiàn)代的 Promise氮块,generator/yield绍载,async/await 友好诡宗。

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

使用 XHR 發(fā)送一個 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 后击儡,頓時看起來好一點

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

使用 ES6 的 箭頭函數(shù) 后:

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

現(xiàn)在看起來好很多了塔沃,但這種 Promise 的寫法還是有 Callback 的影子,而且 promise 使用 catch 方法來進行錯誤處理的方式有點奇怪阳谍。不用急蛀柴,下面使用 async/await 來做最終優(yōu)化:

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

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

duang~~ 的一聲,使用 await
后豺鼻,寫異步代碼就像寫同步代碼一樣爽综液。await
后面可以跟 Promise 對象,表示等待 Promise resolve()
才會繼續(xù)向下執(zhí)行儒飒,如果 Promise 被 reject()
或拋出異常則會被外面的 try...catch
捕獲谬莹。
Promise,generator/yield桩了,await/async 都是現(xiàn)在和未來 JS 解決異步的標準做法附帽,可以完美搭配使用。這也是使用標準 Promise 一大好處井誉。最近也把項目中使用第三方 Promise 庫的代碼全部轉成標準 Promise士葫,為以后全面使用 async/await 做準備。
另外送悔,F(xiàn)etch 也很適合做現(xiàn)在流行的同構應用慢显,有人基于 Fetch 的語法,在 Node 端基于 http 庫實現(xiàn)了 node-fetch欠啤,又有人封裝了用于同構應用的 isomorphic-fetch荚藻。

注:同構(isomorphic/universal)就是使前后端運行同一套代碼的意思,后端一般是指 NodeJS 環(huán)境洁段。

總結一下应狱,F(xiàn)etch 優(yōu)點主要有:
語法簡潔,更加語義化

基于標準 Promise 實現(xiàn)祠丝,支持 async/await

同構方便疾呻,使用 isomorphic-fetch

Fetch 啟用方法
下面是重點↓↓↓
先看一下 Fetch 原生支持率:


原生支持率并不高,幸運的是写半,引入下面這些 polyfill 后可以完美支持 IE8+ :
由于 IE8 是 ES3岸蜗,需要引入 ES5 的 polyfill: es5-shim, es5-sham

引入 Promise 的 polyfill: es6-promise

引入 fetch 探測庫:fetch-detector

引入 fetch 的 polyfill: fetch-ie8

可選:如果你還使用了 jsonp,引入 fetch-jsonp

可選:開啟 Babel 的 runtime 模式叠蝇,現(xiàn)在就使用 async/await

Fetch polyfill 的基本原理是探測是否存在 window.fetch
方法璃岳,如果沒有則用 XHR 實現(xiàn)。這也是 github/fetch 的做法悔捶,但是有些瀏覽器(Chrome 45)原生支持 Fetch铃慷,但響應中有中文時會亂碼,老外又不太關心這種問題蜕该,所以我自己才封裝了 fetch-detector
和 fetch-ie8
只在瀏覽器穩(wěn)定支持 Fetch 情況下才使用原生 Fetch犁柜。這些庫現(xiàn)在每天有幾千萬個請求都在使用,絕對靠譜堂淡!
終于馋缅,引用了這一堆 polyfill 后坛怪,可以愉快地使用 Fetch 了。但要小心股囊,下面有坑:
Fetch 常見坑
Fetch 請求默認是不帶 cookie 的袜匿,需要設置 fetch(url, {credentials: 'include'})

服務器返回 400,500 錯誤碼時并不會 reject稚疹,只有網絡錯誤這些導致請求不能完成時居灯,fetch 才會被 reject。

竟然沒有提到 IE内狗,這實在太不科學了怪嫌,現(xiàn)在來詳細說下 IE
IE 使用策略
所有版本的 IE 均不支持原生 Fetch,fetch-ie8 會自動使用 XHR 做 polyfill柳沙。但在跨域時有個問題需要處理岩灭。
IE8, 9 的 XHR 不支持 CORS 跨域,雖然提供 XDomainRequest
赂鲤,但這個東西就是玩具噪径,不支持傳 Cookie!如果接口需要權限驗證数初,還是乖乖地使用 jsonp 吧找爱,推薦使用 fetch-jsonp。如果有問題直接提 issue泡孩,我會第一時間解決车摄。
標準 Promise 的不足
由于 Fetch 是典型的異步場景,所以大部分遇到的問題不是 Fetch 的仑鸥,其實是 Promise 的吮播。ES6 的 Promise 是基于 Promises/A+ 標準,為了保持簡單簡潔眼俊,只提供極簡的幾個 API意狠。如果你用過一些牛 X 的異步庫,如 jQuery(不要笑) 泵琳、Q.js 或者 RSVP.js摄职,可能會感覺 Promise 功能太少了誊役。
沒有 Deferred
Deferred 可以在創(chuàng)建 Promise 時可以減少一層嵌套获列,還有就是跨方法使用時很方便。ECMAScript 11 年就有過 Deferred 提案蛔垢,但后來沒被接受击孩。其實用 Promise 不到十行代碼就能實現(xiàn) Deferred:es6-deferred。現(xiàn)在有了 async/await鹏漆,generator/yield 后巩梢,deferred 就沒有使用價值了创泄。
沒有獲取狀態(tài)方法:isRejected,isResolved
標準 Promise 沒有提供獲取當前狀態(tài) rejected 或者 resolved 的方法括蝠。只允許外部傳入成功或失敗后的回調鞠抑。我認為這其實是優(yōu)點,這是一種聲明式的接口忌警,更簡單搁拙。
缺少其它一些方法:always,progress法绵,finally
always 可以通過在 then 和 catch 里重復調用方法實現(xiàn)箕速。finally 也類似。progress 這種進度通知的功能還沒有用過朋譬,暫不知道如何替代盐茎。
最后
Fetch 替換 XHR 只是時間問題,現(xiàn)在看到國外很多新的庫都默認使用了 Fetch徙赢。
最后再做一個大膽預測:由于 async/await 這類新異步語法的出現(xiàn)字柠,第三方的 Promise 類庫會逐漸被標準 Promise 替代,使用 polyfill 是現(xiàn)在比較明智的做法狡赐。

原文地址:https://github.com/camsong/blog/issues/2

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末募谎,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子阴汇,更是在濱河造成了極大的恐慌数冬,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件搀庶,死亡現(xiàn)場離奇詭異拐纱,居然都是意外死亡,警方通過查閱死者的電腦和手機哥倔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門秸架,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人咆蒿,你說我怎么就攤上這事东抹。” “怎么了沃测?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵缭黔,是天一觀的道長。 經常有香客問我蒂破,道長馏谨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任附迷,我火速辦了婚禮惧互,結果婚禮上哎媚,老公的妹妹穿的比我還像新娘。我一直安慰自己喊儡,他們只是感情好拨与,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著艾猜,像睡著了一般截珍。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上箩朴,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天岗喉,我揣著相機與錄音,去河邊找鬼炸庞。 笑死钱床,一個胖子當著我的面吹牛,可吹牛的內容都是我干的埠居。 我是一名探鬼主播查牌,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼滥壕!你這毒婦竟也來了纸颜?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤绎橘,失蹤者是張志新(化名)和其女友劉穎胁孙,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體称鳞,經...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡涮较,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了冈止。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片狂票。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖熙暴,靈堂內的尸體忽然破棺而出闺属,到底是詐尸還是另有隱情,我是刑警寧澤周霉,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布掂器,位于F島的核電站,受9級特大地震影響诗眨,放射性物質發(fā)生泄漏唉匾。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一匠楚、第九天 我趴在偏房一處隱蔽的房頂上張望巍膘。 院中可真熱鬧,春花似錦芋簿、人聲如沸峡懈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽肪康。三九已至,卻和暖如春撩穿,著一層夾襖步出監(jiān)牢的瞬間磷支,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工食寡, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留雾狈,地道東北人。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓抵皱,卻偏偏與公主長得像善榛,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子呻畸,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內容

  • 原諒我做一次標題黨伤为,Ajax 不會死咒循,傳統(tǒng) Ajax 指的是 XMLHttpRequest(XHR),未來現(xiàn)在已被...
    9a9Hbx閱讀 14,989評論 17 161
  • Asynchronous JavaScript and XML(異步的 JavaScript 和 XML) XHR...
    KeKeMars閱讀 2,868評論 1 2
  • 異步編程對JavaScript語言太重要绞愚。Javascript語言的執(zhí)行環(huán)境是“單線程”的剑鞍,如果沒有異步編程,根本...
    呼呼哥閱讀 7,311評論 5 22
  • 回調函數(shù) 最原始的callback爽醋,優(yōu)點是簡單蚁署、容易理解,當然也有很嚴重的缺點是不利于代碼的閱讀和維護蚂四,多了之后的...
    席小白閱讀 324評論 3 4
  • 現(xiàn)在是凌晨三點光戈,還是睡不著。臉扽在桌上遂赠,左上角的位置久妆,擺著一盞臺燈,燈泡里的鎢絲打出的顏色是冷白色的跷睦,掩黑色的燈布...
    4e38ebe82a21閱讀 315評論 0 2