八 Vue學習 fetch請求

1:import {login, getAdminInfo} from '@/api/getData'(從api/getData.js中import login函數。)
  看一下以下的getData.js文件,其中export了login函數,因此其餘地方能夠調用。
import fetch from '@/config/fetch'

export const login = data => fetch('/admin/login', data, 'POST');

   繼續看fetch.js函數:node

import { baseUrl } from './env'

export default async(url = '', data = {}, type = 'GET', method = 'fetch') => {
    type = type.toUpperCase();
    url = baseUrl + url;

    if (type == 'GET') {
        let dataStr = ''; //數據拼接字符串
        Object.keys(data).forEach(key => {
            dataStr += key + '=' + data[key] + '&';
        })

        if (dataStr !== '') {
            dataStr = dataStr.substr(0, dataStr.lastIndexOf('&'));
            url = url + '?' + dataStr;
        }
    }

    if (window.fetch && method == 'fetch') {
        let requestConfig = {
            credentials: 'include',
            method: type,
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json'
            },
            mode: "cors",
            cache: "force-cache"
        }

        if (type == 'POST') {
            Object.defineProperty(requestConfig, 'body', {
                value: JSON.stringify(data)
            })
        }
        
        try {
            const response = await fetch(url, requestConfig);
            const responseJson = await response.json();
            return responseJson
        } catch (error) {
            throw new Error(error)
        }
    } else {  // 若是瀏覽器不支持fetch return new Promise((resolve, reject) => {
            let requestObj;
            if (window.XMLHttpRequest) {
                requestObj = new XMLHttpRequest();
            } else {
                requestObj = new ActiveXObject;
            }

            let sendData = '';
            if (type == 'POST') {
                sendData = JSON.stringify(data);
            }

            requestObj.open(type, url, true);
            requestObj.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            requestObj.send(sendData);

            requestObj.onreadystatechange = () => {
                if (requestObj.readyState == 4) {
                    if (requestObj.status == 200) {
                        let obj = requestObj.response
                        if (typeof obj !== 'object') {
                            obj = JSON.parse(obj);
                        }
                        resolve(obj)
                    } else {
                        reject(requestObj)
                    }
                }
            }
        })
    }
}

fetch:  傳統 Ajax 指的是 XMLHttpRequest(XHR),如今已被 Fetch替代; Fetch API 是基於 Promise 設計,有必要先學習一下 Promisegit

XMLHttpRequest:是一個 API,它爲客戶端提供了在客戶端和服務器之間傳輸數據的功能。它提供了一個經過 URL 來獲取數據的簡單方式,而且不會使整個頁面刷新。這使得網頁只更新一部分頁面而不會打擾到用戶。XMLHttpRequest 在 AJAX 中被大量使用;能夠取回全部類型的數據資源,並不侷限於 XML。並且除了 HTTP ,它還支持 file 和 ftp 協議。github

ActiveXObject:  與XMLHttpRequest差別很小,這二者是在不一樣瀏覽器上使用的。json

IE裏面:
new ActiveXObject("Msxml2.XMLHTTP")
new ActiveXObject("Microsoft.XMLHTTP")
Mozilla和Safari裏面:
new XMLHttpRequest()

Fetch VS XHR(XMLHttpRequest):

XMLHttpRequest 是一個設計粗糙的 API,不符合關注分離(Separation of Concerns)的原則,配置和調用方式很是混亂,並且基於事件的異步模型寫起來也沒有現代的 Promise,generator/yield,async/await 友好。後端

Fetch 的出現就是爲了解決 XHR 的問題,拿例子說明:api

使用 XHR 發送一個 json 請求通常是這樣:promise

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 的 箭頭函數 後:服務器

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

如今看起來好不少了,但這種 Promise 的寫法仍是有 Callback 的影子,並且 promise 使用 catch 方法來進行錯誤處理的方式有點奇怪。不用急,下面使用 async/await 來作最終優化:babel

注:async/await 是很是新的 API,屬於 ES7,目前尚在 Stage 1(提議) 階段,這是它的完整規範。使用 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() 纔會繼續向下執行,若是 Promise 被 reject() 或拋出異常則會被外面的 try...catch 捕獲。

Promise,generator/yield,await/async 都是如今和將來 JS 解決異步的標準作法,能夠完美搭配使用。這也是使用標準 Promise 一大好處。最近也把項目中使用第三方 Promise 庫的代碼所有轉成標準 Promise,爲之後全面使用 async/await 作準備。

另外,Fetch 也很適合作如今流行的同構應用,有人基於 Fetch 的語法,在 Node 端基於 http 庫實現了 node-fetch,又有人封裝了用於同構應用的 isomorphic-fetch

注:同構(isomorphic/universal)就是使先後端運行同一套代碼的意思,後端通常是指 NodeJS 環境。

總結一下,Fetch 優勢主要有:

  1. 語法簡潔,更加語義化

  2. 基於標準 Promise 實現,支持 async/await

  3. 同構方便,使用 isomorphic-fetch

 

上面的代碼的邏輯是:若是瀏覽器支持Fetch,就用fetch; 不然就用XHR

 


Let VS Var:
  • let : 變量只能聲明一次
  • var : 變量能夠屢次聲明
let是ES6的新運算let的好處是當咱們寫代碼比較多的時候能夠避免在不知道的狀況下重複聲明變量
相關文章
相關標籤/搜索