八 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函數:

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 設計,有必要先學習一下 Promise

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

ActiveXObject:  與XMLHttpRequest差異很小,這兩者是在不同瀏覽器上使用的。

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 的問題,拿例子說明:

使用 XHR 發送一個 json 請求一般是這樣:

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 來做最終優化:

注: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的好處是當我們寫代碼比較多的時候可以避免在不知道的情況下重復聲明變量

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM