Fetch:ajax替代品(譯文)

Fetch概念

fetch身為H5中的一個新對象膀篮,他的誕生,是為了取代ajax的存在而出現(xiàn)晃洒,主要目的僅僅只是為了結(jié)合ServiceWorkers垒玲,來達到以下優(yōu)化:

  1. 優(yōu)化離線體驗
  2. 保持可擴展性

當然如果ServiceWorkers和瀏覽器端的數(shù)據(jù)庫IndexedDB配合,那么恭喜你岖免,每一個瀏覽器都可以成為一個代理服務(wù)器一樣的存在岳颇。(然而我并不認為這樣是好事,這樣會使得前端越來越重颅湘,走以前c/s架構(gòu)的老路)

能力檢測

如果你想知道自己的瀏覽器是否支持Fetch话侧,只需要簡單new Request或new Response或 new Headers試試就知道了。對于這三個對象是不是非常眼熟闯参,對沒錯瞻鹏,這就是http三劍客,請求鹿寨,響應(yīng)和頭對象新博。

當然那些檢測還是很麻煩,最簡單實用的就是這樣做

        if (window.fetch) {
            //用fetch做一些事情
         }else{
           //用ajax做一些事情
         }

注意:文章通篇在對比的是fetch和原生ajax(既XMLHttpRequest)脚草,而不是jq中被包裝過的ajax赫悄。

簡單的fetch請求

現(xiàn)在我們來設(shè)置一個非常簡單且基本的fetch請求,如下代碼:

var img =document.querySelector("img");

fetch('flower.jpg').then(function(response){
        return response.blob();
}).then(function(myblob){
        var objectURL = URL.createObjectURL(myBlob);
        myImage.src =objectURL;
});

當然你要是看不懂這個寫法馏慨,也沒有關(guān)系埂淮,可以先去學(xué)習(xí)下ES6中promise的用法,或者promise/A+規(guī)范写隶;

在這邊我們請求了一個flower.jpg的圖片倔撞,請求完成之后用URL.createObjectURL的方式轉(zhuǎn)化為一個url,最后把它賦予img節(jié)點的src屬性樟澜。

當然這邊的response對象的blob方法返回的是一個promise對象误窖,所以可以這樣鏈式調(diào)用叮盘。

注意:如果不做特別設(shè)置,默認情況下是get方法霹俺,如果想要使用別的方法柔吼,或者需要設(shè)置特別的http頭什么的,則需要用到headers和request對象丙唧,或者fetch的額外選項(感覺只是對headers和request的包裝)愈魏。

設(shè)置request的fetch請求

你可以通過request的構(gòu)造函數(shù)新建一個request對象,并把它做為參數(shù)傳入fetch中想际,類似下面這樣:

    var myHeaders = new Headers();
    var myInit = { 
                      method: 'GET', 
                      headers: myHeaders, 
                      mode: 'cors', 
                      cache: 'default' 
                   };
    var myRequest = new Request('flowers.jpg',myInit);
    fetch(myRequest, myInit)
    .then(function(response) {
             return response.blob();
            })
    .then(function(myBlob) {
             var objectURL = URL.createObjectURL(myBlob); 
             myImage.src = objectURL;
            });

當然我們也可以通過把一個舊的request對象傳入一個request的構(gòu)造函數(shù)培漏,這樣的我們就可以獲得一個拷貝之后的request對象。

var anotherRequest = new Request(myRequest,myInit);

Headers對象

Headers對象允許你通過Header構(gòu)造函數(shù)來創(chuàng)建胡本,一個Headers對象只是一個簡單的鍵值對集合的map牌柄,當然,里面的鍵值對必須符合http協(xié)議侧甫。(由此可見《http權(quán)威指南》是一本好書)珊佣。

  • 設(shè)置Headers對象內(nèi)容的方式一:
var content = "Hello World";
var myHeaders = new Headers();
myHeaders.append("Content-Type", "text/plain");
myHeaders.append("Content-Length", content.length.toString());
myHeaders.append("X-Custom-Header", "ProcessThisImmediately");
  • 設(shè)置Headers對象內(nèi)容的方式二:
myHeaders = new Headers({
         "Content-Type": "text/plain",
         "Content-Length": content.length.toString(), 
        "X-Custom-Header": "ProcessThisImmediately"
        });

當然Headers里面的內(nèi)容是可以查詢和設(shè)置:

console.log(myHeaders.has("Content-Type")); // true
console.log(myHeaders.has("Set-Cookie")); // false
myHeaders.set("Content-Type", "text/html");
myHeaders.append("X-Custom-Header", "AnotherValue"); 
console.log(myHeaders.get("Content-Length")); // 11
console.log(myHeaders.getAll("X-Custom-Header")); // ["ProcessThisImmediately", "AnotherValue"] 
myHeaders.delete("X-Custom-Header");
console.log(myHeaders.getAll("X-Custom-Header")); // [ ]

但是這里面的有些操作僅僅在 ServiceWorkers
中有用。

如果你對header的key設(shè)置了一個不符合http協(xié)議規(guī)范中的key,(比如你對request的header設(shè)置了response特有的header)披粟,那么js在嚴格守護的模式下會報TypeError的錯誤咒锻。例如:

var myResponse = Response.error();
try { 
       myResponse.headers.set("Origin", "http://mybank.com");
      } catch(e) {
        console.log("Cannot pretend to be a bank!");
      }

一個比較好的用例,就是在處理數(shù)據(jù)之前守屉,先檢查下response中的content-type值惑艇。例如:

fetch(myRequest)
.then(function(response) { 
      var contentType = response.headers.get("content-type"); 
      if(contentType && contentType.indexOf("application/json") !== -1) { 
           return response.json().then(function(json) { 
                  // process your JSON further 
                   });
        } else { 
             console.log("Oops, we haven't got JSON!"); 
          }
      });

Guard(守護模式)

每一個Headers對象都有一個Guard的屬性,該屬性控制著該頭節(jié)點是否可以設(shè)置別的key-value值(鍵值對)拇泛。目前在web中Guard的屬性并沒有被暴露出來滨巴,因此你在瀏覽器中是無法獲得該屬性的。

Guard擁有以下幾個屬性

none: 默認的.
request: 對request對象守護 (Request.headers).
request-no-cors: 設(shè)置Request.mode 的值為no-cors碰镜,request中的headers守護模式值兢卵。
response:Response.headers的守護級別。
immutable: 經(jīng)常用于ServiceWorkers; headers 變?yōu)橹蛔x绪颖。

** 注意:你也許無法在requeset中設(shè)置"Content-Length",類似的甜奄,在response中無法設(shè)置"Set-Cookie"柠横,因為在ServiceWorkers中是不被允許設(shè)置cookie的。

Response

正如你在上面看到的课兄,response只有在fetch對象的狀態(tài)處于resolved的情況下才會在返回牍氛。(其實是只有當fetch這個異步操作成功之后,response對象會作為一個參數(shù)烟阐,傳入到回掉函數(shù)中搬俊。)

當然我們也可以通過Response的構(gòu)造函數(shù)來實現(xiàn)紊扬,但是這個對象只有在ServiceWorkers中是有用的,當然你也可以在window中監(jiān)聽fetch事件唉擂,然后調(diào)用event的responseWith方法中使用餐屎,如下:

var myBody = new Blob();
addEventListener('fetch', function(event) { 
          event.respondWith( new Response(myBody, { 
                    headers: {
                         "Content-Type" : "text/plain" }
                     }) 
                 );
            } );

以下是我們經(jīng)常用的到的response屬性:

  • Response.status :響應(yīng)的狀態(tài)碼。
  • Response.statusText :響應(yīng)狀態(tài)文玩祟。
  • Response.ok :返回的是一個Boolean值腹缩,只要狀態(tài)碼在200-299之間,就返回true空扎。

** 注意:Response的靜態(tài)方法中 error()redirect()返回的是也都是Response對象藏鹊,但是只有在Service Workers中有用。

Body

這邊的body指的是請求和響應(yīng)的體转锈,支持一下幾種數(shù)據(jù)類型:

當然body都有相對的擴展方法去獲取這些類型的數(shù)據(jù)盘寡,這些方法返回的值是一個promise對象,基本上都是基于stream(流)的思想撮慨。

于是我們就可以用以下的方式來使用fetch:

var form = new FormData(document.getElementById('login-form'));
fetch("/login", { 
    method: "POST", 
    body: form
    })

不要擔(dān)心在傳這些數(shù)據(jù)的時候宴抚,Content-type的值,瀏覽器會智能的幫我們設(shè)置這些甫煞,不管在request中還是response中菇曲,當然你要是手工指定也是可以的。

總結(jié)

fetch相比較原生ajax更為靈活抚吠,提供的數(shù)據(jù)類型更多常潮,更接近底層。但是目前看來楷力,想要取代ajax喊式,還需要一段時間,因為ajax二代+類jQuery工具庫的幫助萧朝,fetch在常規(guī)應(yīng)用方面還是相形見絀的岔留。

參考資料:
Using Fetch
[譯] JavaScript Fetch API

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市检柬,隨后出現(xiàn)的幾起案子献联,更是在濱河造成了極大的恐慌,老刑警劉巖何址,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件里逆,死亡現(xiàn)場離奇詭異,居然都是意外死亡用爪,警方通過查閱死者的電腦和手機原押,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來偎血,“玉大人诸衔,你說我怎么就攤上這事盯漂。” “怎么了笨农?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵就缆,是天一觀的道長。 經(jīng)常有香客問我磁餐,道長违崇,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任诊霹,我火速辦了婚禮羞延,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘脾还。我一直安慰自己伴箩,他們只是感情好,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布鄙漏。 她就那樣靜靜地躺著嗤谚,像睡著了一般。 火紅的嫁衣襯著肌膚如雪怔蚌。 梳的紋絲不亂的頭發(fā)上巩步,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天,我揣著相機與錄音桦踊,去河邊找鬼椅野。 笑死,一個胖子當著我的面吹牛籍胯,可吹牛的內(nèi)容都是我干的竟闪。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼杖狼,長吁一口氣:“原來是場噩夢啊……” “哼炼蛤!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蝶涩,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤理朋,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后子寓,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體暗挑,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年斜友,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片垃它。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡鲜屏,死狀恐怖烹看,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情洛史,我是刑警寧澤惯殊,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站也殖,受9級特大地震影響土思,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜忆嗜,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一己儒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧捆毫,春花似錦闪湾、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至濒憋,卻和暖如春何暇,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背凛驮。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工裆站, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人辐烂。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓遏插,卻偏偏與公主長得像,于是被迫代替她去往敵國和親纠修。 傳聞我的和親對象是個殘疾皇子胳嘲,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容