axios、fetch 和 ajax 等的區別詳解


  主體內容來自: https://www.jianshu.com/p/8bc48f8fde75

  axios、fetch 和 ajax的區別 在網絡上存在很多文章。個人現針對自己的情況,來重新整理一份,便於自己記憶和理解。內容參考了網絡上的眾多文章。

 

XMLHttpRequest

  瀏覽器通過XMLHttpRequest 對象進行 http 通信。

  傳統Ajax 指的是 XMLHttpRequest(XHR),最早出現的向后端發送請求的技術,隸屬於原始 js 中, 核心使用 XMLHttpRequest 對象,多個請求之間如果有先后關系的話,就會出現 回調地獄

 

  推薦一篇有關 XMLHttpRequest 的文章:XMLHttpRequest ——必知必會

 

  常用語法:

  一個簡單的 http 請求

let xhr = new XMLHttpRequest();
xhr.open('GET', '/url', true);
xhr.send();

    

  一個稍微完整的 http 請求

let xhr = new XMLHttpRequest();
// 請求成功回調函數
xhr.onload = e => {
    console.log('request success');
};
// 請求結束
xhr.onloadend = e => {
    console.log('request loadend');
};
// 請求出錯
xhr.onerror = e => {
    console.log('request error');
};
// 請求超時
xhr.ontimeout = e => {
    console.log('request timeout');
};
// 請求回調函數.XMLHttpRequest標准又分為Level 1和Level 2,這是Level 1和的回調處理方式
// xhr.onreadystatechange = () => {
//    if (xhr.readyState !== 4) {
//      return;
//    }
//    const status = xhr.status;
//    if ((status >= 200 && status < 300) || status === 304) {
//      console.log('request success');
//    } else {
//      console.log('request error');
//    }
//  };

xhr.timeout = 0; // 設置超時時間,0表示永不超時
// 初始化請求
xhr.open('GET/POST/DELETE/...', '/url', true || false);
// 設置期望的返回數據類型 'json' 'text' 'document' ...
xhr.responseType = '';
// 設置請求頭
xhr.setRequestHeader('', '');
// 發送請求
xhr.send(null || new FormData || 'a=1&b=2' || 'json字符串');

  這個是從網上找的。如果粗看官網提供的文檔,可能需要很久的時間才能明白究竟怎么用。此處我先列出引用下。

JQuery ajax

  菜鳥教程:AJAX 是一種與服務器交換數據的技術,可以在不重新載入整個頁面的情況下更新網頁的一部分。

  基本語法:

$.ajax({
    type: 'POST',  // GET 或 POST
   url: url,    // 發送請求的 URL
   data: data,  // 要發送到服務器的數據
   dataType: dataType, // 預期的服務器響應的數據類型
   success: function () {}, // 請求成功時運行的函數
   error: function () {}   // 請求失敗要運行的函數
});

  缺點:

  1、針對MVC的編程,不符合前端MVVM的浪潮

  2、基於原生XHR開發,而XHR本身的架構不清晰 (我覺得此處應該是說官方給出的文檔架構不清晰。)

  3、JQuery整個項目太大,單純使用Ajax 卻要引入整個JQuery,非常的不合理(采取個性化打包的方案又不能享受CDN服務)

  4、不符合關注分離(Separation of Concerns)的原則

  5、配置和調用方法非常的混亂,而且基於事件的異步模型不友好。(配置和調用方法非常的混亂:想做封裝處理的時候,配置不好處理,需要做判斷,如果方法不公用 就每次調用都得ajax一次,代碼冗余。 )

  PS: MVVM (Model-View-ViewModel) 源自於經典的Model-View-Controller (MVC)模式。

    MVVM的出現促進了GUI前端開發與后端業務邏輯的分離,極大地提高了前端開發效率。

    MVVM 的核心是 ViewModel 層,它就像一個中轉站(value converter),負責轉換Model中的數據對象來讓數據變得更容易管理和使用,該層向上與視圖層進行雙向數據綁定,向下與Model層通過接口請求進行數據交互,起呈上啟下作用。View 層展現的不是 Model層的數據,而是ViewModel 的數據,由 ViewModel 負責與Model層交互,這就完全解耦了View層和Model層,這個解耦是至關重要的,它是前后端分離方案實施的最重要一環。

  

 

axios

  axios 是一個基於 Promise 的 http請求庫,可以用在瀏覽器和 node.js 中,本質上也是對原生XHR的封裝,只不過它是Promise 的實現版本,符合最新的ES規則。

  基本語法:

const axios = require('axios')

// Make a request for a user with a given ID
axios.get('/url', {params})    // or axios.post ...
        .then(function(response){
                console.log(response)
        })
        .catch(function(error){
           console.log(error) 
        })

// Want to use async/await? Add the `async` keyword to your outer function/method
async function getUser(){
    try{
        const response = await axios.get('/user')
        console.log(response)                   
    }catch(error){
         console.error(error)  
    }  
}

  NOTE:  async/await 是ES6 中的內容,在 IE 及一些老版本的瀏覽器不支持,請謹慎使用。

  

  axios 的特征:

  1、從瀏覽器中創建XMLHttpRequest

  2、支持 Promise API

  3、客戶端支持防止 CSRF

  4、提供了一些並發請求的接口(重要,方便了很多的操作)

  5、從 node.js 創建 http 請求

  6、攔截請求和響應

  7、轉換請求和響應數據

  8、取消請求

  9、自動轉換JSON數據

PS:防止CSRF(跨站請求偽造):就是讓你的每個請求都帶一個從cookie中拿到的key,根據瀏覽器同源策略,假冒的網站是拿不到你 cookie 中的key的,這樣,后台就可以輕松辨別出這個請求是否是用戶在假冒網站上的誤導輸入,從而采取正確的策略。

 

fetch

// 一個簡單的fetch 請求
fetch('http://example.com/movies.json')
    .then(function(response){
        return response.json()
    })
    .then(function(myJson){
       console.log(myJson) 
    })


// 一個帶有參數的fetch請求
postData('http://example.com/answer',{answer: 42})
    .then(data => console.log(data))  // JSON from 'response.json()' call
    .catch(error => console.error(error))

function postData(url, data) {
  // Default options are marked with *
  return fetch(url, {
       body: JSON.stringify(data),  // must match 'Content-Type' header
       cache: 'no-cache',  // * default, no-cache, reload, force-cache, only-if-cached
        headers: {
            'user-agent': 'Mozilla/4.0 MDN Example',
             'content-type': 'application/json'
        },
        method: 'POST', // *GET, POST, PUT, DELETE, etc.
        mode: 'cors', // no-cors, cors, *same-origin
        redirect: 'follow', // manual, *follow, error
        referrer: 'no-referrer', // *client, no-referrer    
  })    
  .then(response => response.json()) // parses response to JSON      

  fetch 號稱是 AJAX 的替代品,是在 ES6 出現的,使用了ES6 中的 promise 對象。Fetch 是基於 promise 設計的。 Fetch 的代碼結構比起 ajax 簡單多了, 參數有點像 JQuery ajax。 但是,一定要記住: fetch 不是 ajax的進一步封裝,而是原生 JS , 沒有使用 XMLHttpRequest 對象。

  fetch 的優點:

  1、符合關注分離,沒有將輸入、輸出 和用事件來跟蹤的狀態混雜在一個對象中

  2、更好更方便的寫法

 

  坦白說,上面的理由對我來說完全沒有什么說服力,因為不管是Jquery還是Axios都已經幫我們把xhr封裝的足夠好,使用起來也足夠方便,為什么我們還要花費大力氣去學習fetch?

我認為fetch的主要優勢就是:

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

  2、基於標准 Promise 實現,支持 async / await

  3、同構方便,使用[isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)

  4、更加底層,提供的 API 豐富 (request, response)

  5、脫離了 XHR,是 ES  規范中新的實現方式。

  

  最近在使用fetch的時候,也遇到了不少的問題:
fetch是一個低層次的API,你可以把它考慮成原生的XHR,所以使用起來並不是那么舒服,需要進行封裝。

  例如:

  1、fetch 只對網絡請求報錯,對400,500都當作成功的請求,服務器返回400, 500 錯誤碼時並不會 reject,只有網絡錯誤這些導致請求不能完成時, fetch 才會被 reject。需要封裝去處理。

  2、fetch 默認不會帶 cookie,需要添加配置項: fetch(url, {credentials: 'include'})

  3、fetch 不支持 abort (xhr 有個 xhr.abort 方法可以直接阻斷請求),不支持超時控制,使用 setTimeout 及 Promise.reject 的實現的超時控制並不能阻止請求,請求過程繼續在后台運行,造成了流量的浪費。

  4、fetch 沒有辦法原生監測請求的進度,而 XHR 可以。

  5、fetch 兼容性並不太好,IE 不支持

  PS:xhr send 完之后,本質請求已經發送了, 進入網絡傳輸了,流量浪費已經發生了,abort只是在你未來某個時機調用,不想要這個請求了,那么即使遠端服務器返回數據了,我瀏覽器拿到了,也不執行回調,因為已經abort了這個請求。(流量浪費已經發生了,只是abort 可以更好地控制要不要執行請求的回調。)

 

總結:axios既提供了並發的封裝,也沒有fetch的各種問題,而且體積也較小,當之無愧現在最應該選用的請求的方式。

 


並發 & 並行:

並發:在操作系統中,指一個時間段中有幾個程序都處於已啟動運行到運行完畢之間,且這幾個程序都是在同一個處理機上運行,但 任一個時刻點上 只有一個程序 在處理機上運行。

並行:在操作系統中,一組程序 按獨立異步 的速度執行,無論從微觀還是宏觀,程序都是 一起執行的

 

 fetch 中的 AbortController:

  AbortController 接口代表一個控制器對象,允許你在需要時中止一個或多個DOM請求。

  這是一個實驗中的功能。此功能某些瀏覽器尚在開發中。詳情請見:https://developer.mozilla.org/zh-CN/docs/Web/API/FetchController

 

什么是回調地獄?

  由於某些業務的需要, 每個接口都需要依賴前一個接口的返回,在代碼中一次性寫多層的回調嵌套,回調嵌套后的代碼維護難度 和 無法快速排除bug ,這個就被稱為 回調地獄。

  該如何解決回調地獄?在工作中的一般處理方式是使用 promise 或者async

  promise: 如 req1().then(req2).then(req3)

  Promise 的特性:(等待:pending;完成:resolve   拒絕:reject)

    1、promise 內部 分 微任何 和 宏任務 

    2、promise 本身是同步的,但它的成功的回調 .then 方法 是異步的。

    3、promise 的狀態是不可逆的

    4、then return 出去的值,會被后面的 then 接收,如果后面還跟着 then 的話,catch同理

    5、promise 不管返回什么值,都會被包裝成一個promise 對象,即使這個返回值是error

    6、then 接收到的值,如果不是一個函數,會穿透到后面的 then

    7、promise 對象如果 resolve 或者 reject 的也是一個 promise 對象,那么 promise 對象的狀態會由 resolve 或者 reject 的 promise 對象的狀態決定。


 

文章推薦:

Axios 源碼深度剖析 - AJAX新王者: https://www.imooc.com/article/32292?block_id=tuijian_wz

並發和並行,異步與多線程區別:https://blog.csdn.net/woliuyunyicai/article/details/45165869

 


免責聲明!

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



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