隨着前端異步的發展, XHR 這種耦合方式的書寫不利於前端異步的 Promise 回調. 並且,寫起來也是很複雜. fetch API 原本是在 SW(ServiceWorkers) 中提出的, 不過, 後面以爲好用, 就把他掛載到 window 對象下. 這樣, 在前端的正常通訊中, 咱們也能夠直接調用. 但, fetch 畢竟比較新, 看一下他的兼容性.php
在 PC 端上, 就 FF, Opera 和 Chrome 比較 fashion. mobile 的話, 基本上是不能用的. 固然, 前端一直是個擁抱變化的職業, 官方已經有一個現成的 polyfill 可使用. 這樣的話, 就不必過多擔憂.html
每用到一個新的 feature, 咱們首先得知道他能不能用. Modernizr 這個庫作的挺好的. 這裏, 咱們簡單的瞭解一下就 ok 了.前端
let isFetch = window.fetch?true:false;
能夠說, fetch 就是 ajax + Promise. 使用的方式和 jquery 提供的 $.ajax() 差很少.jquery
fetch('./api/some.json') .then( function(response) { if (response.status !== 200) { console.log(`返回的響應碼${response.status}`); return; } // 得到後臺實際返回的內容 response.json().then(function(data) { console.log(data); }); } ) .catch(function(err) { console.log('Fetch Error :-S', err); });
上面的 demo 很好的參數了, fetch 的幾個特色.git
then 和 catch 是 promise 自帶的兩個方法, 我這裏就很少說了. 咱們來看一下,json 是幹嗎的.github
由於返回回來的數據不只僅包括後臺的返回的 Text 內容, 還有一些 Headers. 因此在, then 方法裏面返回來的 res 實際上並非咱們在業務中想要的內容. 就和在 XHR 裏返回數據是一個道理, 咱們最終要的是 responseText
這個數據. 而 json() 方法實際作的事情,就是調用 JSON.parse() 處理數據, 而且返回一個新的 Promise. 看一下 polyfill 源碼就應該瞭解.web
this.json = function() { return this.text().then(JSON.parse) }
這裏須要注意的是,fetch 中的 response/request 都是 stream 對象。ajax
上面的 demo 是一個 get 方法的請求, 固然, 除了 get , 還有其餘的 HTTP Method, PUT, DELETE, POST, PATCH 等. 這裏, 咱們就說一個 POST, 其餘方法的基本格式仍是相似的.json
fetch("http://www.example.org/submit.php", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: "this is a post Msg" }).then(function(res) { if (res.ok) { // doSth } else if (res.status == 401) { // doSth } });
看起來 fetch 和 $.ajax 並無多大的區別...
but... fetch 裏面的內容,真很多. 往底層看一看, fetch 其實是 Request,Headers,Response 3個接口的整合. 不過, 這3個只能在 SW 裏面使用. 這裏當作原理,參數一下便可.api
Headers 的操做無非就是 CRUD, 這裏我就不過多贅述,直接看代碼吧:
var content = "Hello World"; var reqHeaders = new Headers(); reqHeaders.append("Content-Type", "text/plain" reqHeaders.append("Content-Length", content.length.toString()); reqHeaders.append("X-Custom-Header", "自定義頭");
固然, 你也可使用字面量的形式:
reqHeaders = new Headers({ "Content-Type": "text/plain", "Content-Length": content.length.toString(), "X-Custom-Header": "自定義頭", });
接下來就是, 頭部的內容的檢測相關.
console.log(reqHeaders.has("Content-Type")); // true console.log(reqHeaders.has("Set-Cookie")); // false reqHeaders.set("Content-Type", "text/html"); reqHeaders.append("X-Custom-Header", "新增自定義頭"); console.log(reqHeaders.get("Content-Length")); // 11 console.log(reqHeaders.getAll("X-Custom-Header")); // ["自定義頭", "新增自定義頭"] reqHeaders.delete("X-Custom-Header"); console.log(reqHeaders.getAll("X-Custom-Header")); // []
不過, 鑑於安全性的考慮, 有時候在多人協做或者子版塊管理時, 對於頭部的限制仍是須要的. 這裏, 咱們能夠經過 guard
屬性, 設置 Headers 的相關策略.
guard 一般能夠取 "immutable", "request", "request-no-cors", "response", "none".
咱們這裏不探討所有, 僅僅看一下 request 這個選項.
當你設置了 request 以後, 若是你設置的 Header 涉及到 forbidden header name (這個是瀏覽器自動設置的), 那麼該次操做是不會成功的.
forbidden header name 一般有.
對比與 fetch, 咱們沒有辦法去設置 Headers的 guard, 因此, 這隻能在 SW 裏使用.
Request 的基本用法和 fetch 差很少.
var uploadReq = new Request("/uploadImage", { method: "POST", headers: { "Content-Type": "image/png", }, body: "image data" }); fetch("/uploadImage", { method: "POST", headers: { "Content-Type": "image/png", }, body: "image data" });
那 fetch 有什麼用呢?
關鍵的地方在於,fetch 實際上就是 request/reponse 的容器,request/response 至關於就是兩個元數據,fetch 只是實際進行的操做。因此,爲了達到更高的複用性,咱們能夠 ajax 的請求,實例化爲一個個具體的對象。
var getName = new Request(...,{//...}); var getGender = new Request(...,{//...}); // 發送請求 fetch(getName) .then((res)=>{}); fetch(getGender) .then((res)=>{});
在瀏覽器裏, 一切請求都逃不過跨域和不跨域的問題. fetch 也是. 對於跨域的請求, 主要的影響仍是體如今 Response 中, 這 fetch Request 這, 沒多大影響. 不過, 咱們須要在 fetch 設置 mode
屬性, 來表示這是一個跨域的請求.
fetch('https://www.villainhr.com/cors-enabled/some.json', {mode: 'cors'}) .then(function(response) { return response.text(); })
經常使用的 mode 屬性值有:
Access-Control-Allow-Origin
. 話句話說, 就是用來處理 script, image 等的請求的. 他是 mode 的默認值.另外, 還有一個關於 cookie 的跨域內容. 在 XHR2 中,咱們瞭解到, withCredentials 這個屬性就是用來設置在進行跨域操做時, 對不一樣域的 Server 是否發送本域的 cookie. 通常設置爲 omit(不發送). 在 fetch 當中, 使用的是 credentials
屬性.
credentials 經常使用取值爲:
因此, 若是你想發送 ajax 時, 帶上 cookie, 那麼你就須要使用 same-origin, 若是想在跨域時也帶上 cookie, 那麼就須要 include.
// 跨域請求 fetch('https://www.villainhr.com/cors-enabled/some.json', {mode: 'cors',credentials:'include'}) .then(function(response) { return response.text(); })
response 應該算和 fetch 最爲接近的一個對象. Response 的實際其實就是 fetch 回調函數傳回的參數. Response 中比較經常使用的屬性有四個: status, statusText, ok, type.
fetch('https://www.villainhr.com/cors-enabled/some.json', {mode: 'cors',credentials:'include'}) .then(function(response) { // ... })
這裏, 咱們主要關心一下 type 上面掛載的一些屬性.
- Cache-Control - Content-Language - Content-Type - Expires - Last-Modified - Pragma
no-cors
發送跨域請求時,會觸發.另外,在 response 上面,還掛載了幾個經常使用的方法: text(),json().
使用方式都是流式 API.
fetch('https://www.villainhr.com/cors-enabled/some.json') .then(function(res) { res.text().then((text)=>{...}) res.json().then((obj)=>{...}) })
咱們經過 ajax 請求數據時,可能會收到,ArrayBuffer,Blob/File,string,FormData 等等。而且,在發送的時候好比:
var form = new FormData(document.getElementById('login-form')); fetch("/login", { method: "POST", body: form })
fetch 會自動設置相關的 Content-Type 的頭。另外,若是咱們能夠手動生成一個響應流(方便後面其餘操做)。
var res = new Response(new File(["chunk", "chunk"], "archive.zip",{ type: "application/zip" }));
由於,req/res 都是以流的形式存在的,即,req/res 的 body 只能被使用一次。至關於就是一個文件從緩存讀到硬盤裏面,那麼原來文件就已經消失了。咱們能夠經過 bodyUsed
去檢查,該對象是否已經被使用。
var res = new Response("one time use"); console.log(res.bodyUsed); // false res.text().then(function(v) { console.log(res.bodyUsed); // true }); console.log(res.bodyUsed); // true res.text().catch(function(e) { console.log("Tried to read already consumed Response"); });
這樣作的緣由主要是爲了讓之後 Web 更好的處理視頻的相關數據。那若是我有時候想要使用屢次,那該怎麼辦?
例如,咱們 Service Worker 中,使用 caches API 緩存響應,而後後面我還要將該響應返回給瀏覽器,那麼這裏 response 流就被使用了兩次。這裏,就和普通的流操做同樣,將該流克隆一份,使用:
addEventListener('fetch', function(evt) { var sheep = new Response("Dolly"); console.log(sheep.bodyUsed); // false var clone = sheep.clone(); console.log(clone.bodyUsed); // false clone.text(); console.log(sheep.bodyUsed); // false console.log(clone.bodyUsed); // true evt.respondWith(cache.add(sheep.clone()).then(function(e) { return sheep; }); });
基本的內容就是上述內容. 若是想更詳細參考的話, 請查閱:
【騰訊雲的1001種玩法】 徵文活動技術文章等你來讀! 點擊查看詳情