Javascript語言將任務的執行模式分紅兩種:同步(Synchronous)和異步(Asynchronous)。vue
在瀏覽器,耗時很長的操做都應該異步執行,避免瀏覽器失去響應,最好的例子就是Ajax操做。經過XHRHttpRequest對象及時監聽完成事件,執行事件回調函數不會堵塞程序運行。jquery
Fetch API 提供了一個 JavaScript接口,用於訪問和操縱HTTP管道的部分,例如請求和響應。它還提供了一個全局 fetch()方法,該方法提供了一種簡單,合乎邏輯的方式來跨網絡異步獲取資源。這種功能之前是使用 XMLHttpRequest實現的。Fetch提供了一個更好的替代方法,能夠很容易地被其餘技術使用,例如 Service Workers。Fetch還提供了單個邏輯位置來定義其餘HTTP相關概念,例如 CORS和HTTP的擴展。web
新的Fetch API是XHRHttpRequest異步請求的另外一種方案,比起其複雜糅雜的寫法,fetch能更簡潔的獲取到數據。ajax
XHRHttpRequest使用事件回調函數容易進入回調地獄,而Fetch Api接收url參數返回Promise對象。json
Fetch 提供了對 Request 和 Response (以及其餘與網絡請求有關的)對象的通用定義。使之從此能夠被使用到更多地應用場景中api
let url = 'http://jsonplaceholder.typicode.com/users' fetch(url).then((res)=>{ console.log(res) }).catch((err)=>{})
將url傳遞給fetch時會當即返回一個promise對象此時的狀態是pending,當promise被經過時會返回一個response對象。若是咱們用習慣了好比jquery封裝好的ajax方法,很容易會覺得上面的res就是返回的data。跨域
fetch 只有在遇到網絡錯誤的時候纔會 reject 這個 promise,好比用戶斷網或請求地址的域名沒法解析等。只要服務器可以返回 HTTP 響應(甚至只是 CORS preflight 的 OPTIONS 響應),promise 必定是 resolved 的狀態。promise
fetch返回Promise對象瀏覽器
response.type有如下幾種緩存
basic 標準值,同源響應
cors 收到一個有效的跨域請求
opaque 跨域請求但服務器沒有返回cors響應頭
可是無效的跨域請求若是像下面這麼寫,其實根本沒法拿到response對象
request.mode用於肯定跨域請求是否致使有效的響應
same-origin 同源狀況下才可請求成功,不然拋出錯誤
好比在有效的跨域請求設置這個模式會提示
Fetch API cannot load http://jsonplaceholder.typico... Request mode is "same-origin" but the URL's origin is not same as the request origin file://.
cors: 表示同域和帶有CORS響應頭的跨域下可請求成功.
cors-with-forced-preflight: 表示在發出請求前, 將執行preflight檢查.
no-cors: 用於跨域相應不帶cors的狀況,此時相應類型爲opaque
根據上面的錯誤修改fetch的模式就能夠返回response對象了,能夠對比發現無效跨域請求並無返回什麼有價值的信息例如url,status,statusText等
reponse.body屬於ReadableStream類型
當讀取CSV等大文件時經過流來讀取,能夠選擇在讀取到要獲取的數據後中止流,而不是獲取到所有響應數據再去查找。
對於經常使用返回的幾種數據類型,可使用blob()、text()、formData()、json(),這幾種方法都會講body標記爲已讀數據,因此想再次獲取的時候就會報錯
好比下面的代碼,真實返回的數據不是json類型的,想利用catch方法去捕獲而後再次返回text類型,瀏覽器時會報TypeError: Already read
fetch(url).then(function(response) { return response.json().catch(function() { return response.text(); }); });
正確的方式是使用clone()方法先對數據進行拷貝,響應數據經過clone並不會被回收,一直留在內存中,直至被讀取
fetch(url).then(function(response) { return response.clone().json().catch(function() { return response.text(); }); });
method:設置請求方法,默認GET方法
credentials fetch方法默認不發送cookies,若是遇到401 Unauthorized沒有權限問題就要看看是否有設置credentials
omit: 從不發送cookies.
same-origin: 只有當URL與響應腳本同源才發送cookies.
include: 老是發送cookies, 即便來自跨域的請求
默認狀況下請求不帶coookie
cache 設置緩存,跟XHR對比在請求時就能夠控制緩存,雖然這是有爭議的,由於這暴露了用戶歷史記錄
default
若是是最新的資源,則返回緩存
若是資源已過時則向服務器發出條件請求;若是服務器指示資源沒有改變則返回緩存;不然從服務器中下載,並更新緩存。
若是沒有找到緩存則發出正常情求,但不緩存資源。
no-store 直接從服務器獲取資源而且不會將資源緩存
reload 直接從服務器獲取資源,而且緩存資源
no-cache
若是資源有效或者過時,瀏覽器會發出一個條件請求,若是服務器返回沒有改變,則返回緩存,不然,從新獲取資源並更新緩存
若是不存在資源則瀏覽器發出正常請求下載並更新緩存
force-cache
若是有緩存直接返回緩存,不然下載更新資源
only-if-cached
若是有緩存直接返回緩存,不然瀏覽器返回錯誤
fetch沒有xhr中的abort()方法來中斷請求
fetch沒有progress進度事件監聽數據,可是你能夠經過獲取content-length計算進度
XHR open方法有最後一個參數設爲false的時候是同步請求,fetch沒有提供同步請求的方法,但同步請求並不經常使用
fetch 並無像XHR的timeout屬性來設置延時
習慣了像是vue-resource等插件封裝好的get,post方法,在使用fetch的時候很容易會被它看似簡潔的api給迷惑
fetch兼容性問題
咱們須要引入fetch 的polyfill,扒開源碼咱們能夠發現實現原理仍是創建在XMLHttpRequest上的,可是因爲polyfill要實現fetch如Blob類文件對象等,在safari和ie上仍是有兼容性問題的
參數傳遞問題
在get請求方式中,咱們仍是隻能像xhr那樣以拼接url字符串的方式來傳遞,這與fetch看起來簡潔的api有點不符。
雖然原生的URLSearchParams 接口定義了用來處理 URL 參數串的方法。可是這個api目前兼容性也是不怎麼好
var paramsString = "q=URLUtils.searchParams&topic=api"
var searchParams = new URLSearchParams(paramsString);
searchParams.append("topic", "webdev");
searchParams.toString(); // "q=URLUtils.searchParams&topic=api&topic=webdev"
在post請求中,數據要以body字段來傳遞參數,也就是說咱們要經常使用的json格式要通過下面格式的轉換,就像XMLHttpRequest那樣
body 能夠是如下任何一種類型的實例:
ArrayBuffer ArrayBufferView (Uint8Array and friends) Blob/File string URLSearchParams FormData
響應數據的問題
在回調函數中咱們首先接受到的是response對象,因爲body是ReadableStream類型,幾乎很難預先判斷數據是什麼類型,也就很難判斷是到底用text()、json()方法解析數據
response對象有一個bodyUsed的屬性初始是false,調用text()、json()等方法會讀取Response對象而且將它設置爲已讀,這時bodyUsed爲true
bodyUsed初始值爲false
- 解決辦法有兩種但都有必定的不足 1.是經過clone加catch方式找到正確的輸出方式,可是要注意調用方法的順序,否則一個json有可能最後仍是以text的方式解析,還要注意的是最後要將response的數據回收或者讀取,由於clone方法的讀取並不影響原來的reponse對象
fetch(url).then(function(response) { return response.json().catch(function() { return response.text(); }); });
2.是經過判斷content-type的方式,若是已知的返回格式很少的狀況下用仍是不錯的選擇
fetch(url).then(function(response) { if (response.headers.get('Content-Type') === 'application/json') { return response.json(); } return response.text(); });
基於promise的fecth方法可讓咱們遠離回調地獄而不須要其餘的封裝。
fetch 將 response.body 設計成 ReadableStream 實際上是很是有前瞻性的,這種設計讓你在請求大致積文件時變得很是有用。