一個基本的fetch操做很簡單。就是經過fetch請求,返回一個promise對象,而後在promise對象的then方法裏面用fetch的response.json()等方法進行解析數據,因爲這個解析返回的也是一個promise對象,因此須要兩個then才能獲得咱們須要的json數據。es6
fetch('http://example.com/movies.json') .then(function(response) { return response.json(); }) .then(function(myJson) { console.log(myJson); });
fetch規範與jQuery.ajax()主要有兩種方式的不一樣:
一、當接收到一個表明錯誤的 HTTP 狀態碼時,好比400, 500,fetch不會把promise標記爲reject, 而是標記爲resolve,僅當網絡故障時或請求被阻止時,纔會標記爲 reject。
二、默認狀況下,fetch 不會從服務端發送或接收任何 cookies, 若是站點依賴於用戶 session,則會致使未經認證的請求(要發送 cookies,必須設置 credentials 選項)。ajax
從這裏能夠看出來,若是咱們要在fetch請求出錯的時候及時地捕獲錯誤,是須要對response的狀態碼進行解析的。又因爲fetch返回的數據不必定是json格式,咱們能夠從header裏面Content-Type獲取返回的數據類型,進而使用正確的解析方法。json
Promise 將異步操做規範化.使用then鏈接, 使用catch捕獲錯誤, 堪稱完美, 美中不足的是, then和catch中傳遞的依然是回調函數, 與心目中的同步代碼不是一個套路.api
爲此, ES7 提供了更標準的解決方案 — async/await. async/await 幾乎沒有引入新的語法, 表面上看起來, 它就和alert同樣易用。跨域
var word = '123', url = 'https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd='+word+'&json=1&p=3'; (async ()=>{ try { let res = await fetch(url, {mode: 'no-cors'});//等待fetch被resolve()後才能繼續執行 console.log(res);//fetch正常返回後才執行 return res;//這樣就能返回res不用擔憂異步的問題啦啦啦 } catch(e) { console.log(e); } })();
檢查返回值的狀態: 上面提到了,由於fetch不會本身reject,因此咱們只可以經過拋出錯誤幫一下它啦。301和302是重定向的狀態碼,這個時候頁面須要跳轉一下,經過window.location實現是否是很perfer呢。promise
checkStatus(response) {//檢查響應狀態 if(response.status >= 200 && response.status < 300) {//響應成功 return response; } if(response.status === 301 || response.status === 302) {//重定向 window.location = response.headers.get('Location'); } const error = new Error(response.statusText); error.data = response; throw error; }
判斷用哪一個fetch的解析函數:這裏經過headers的Content-Type判斷使用哪一個解析方法,由於解析也是異步的,因此仍是用async/await讓程序停在那裏慢慢解析。cookie
async parseResult(response) {//解析返回的結果 const contentType = response.headers.get('Content-Type'); if(contentType != null) { if(contentType.indexOf('text') > -1) { return await response.text() } if(contentType.indexOf('form') > -1) { return await response.formData(); } if(contentType.indexOf('video') > -1) { return await response.blob(); } if(contentType.indexOf('json') > -1) { return await response.json(); } } return await response.text(); }
爲了調用比較好看吧,寫多一個processResult去調用者兩個方法,而後在fetch的then裏面就只須要用這個去獲得結果啦。網絡
async processResult(response) { let _response = this.checkStatus(response) _response = await this.parseResult(_response); return _response; }
把請求後臺的代碼都寫在_request裏面,而後get和post裏面就封裝一下參數。session
async _request(url, init, headers = {}) { try { let options = _.assign( { credentials: 'include',//容許跨域 }, init ); options.headers = Object.assign({}, options.headers || {}, headers || {}); let response = await fetch(url, options); response = await this.processResult(response);//這裏是對結果進行處理。包括判斷響應狀態和根據response的類型解析結果 return response; } catch(error) { throw error; return null; } } async get(api, data = {}, headers = {}, config = {}) { const query = _.isEmpty(data) ? '' : `json=${encodeURIComponent(JSON.stringify(data))}`; return await this._request(`${api}?${query}`, headers, {}, config); } async post(api, data = {}, headers = {}, config = {}) {//經過headers決定要解析的類型 const _headers = { 'Content-Type': 'application/x-www-form-urlencoded', ...headers, }; let formBody = null; if(_headers['Content-Type'] && _headers['Content-Type'].indexOf('application/x-www-form-urlencoded')>-1) { formBody = new URLSearchParams(); for(let k in data) {//遍歷一個對象 if(typeof(data[k]) === 'object') { formBody.append(k, JSON.stringify(data[k])); } else { formBody.append(k, data[k]); } } } return await this._request( api, { method: 'POST', headers: _headers, body: formBody, }, {}, config, ) }
把上面這些代碼到寫在一個http類裏面app
import 'isomorphic-fetch' import 'es6-promise' import _ from 'lodash'; class http { checkStatus(response) {} async parseResult(response) {} async processResult(response) {} async _request(url, init, headers = {}) {} async get(api, data = {}, headers = {}, config = {}) {} async post(api, data = {}, headers = {}, config = {}) {} } let http = new Http(); export default http;
而後調用的時候
import http from '../../common/http' getData() { //form類型 http.post('/api/submitComment', {a: 'hhhh'}).then((data) => { console.log(data);//輸出返回的數據 }) //json類型 http.post('/api/submitComment', {a: 'hhhh'}, {'content-type': 'application/json' }).then((data) => { console.log(data);//輸出返回的數據 }) }