axios、fetch 和 ajax 等的區別詳解

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

  axios、fetch 和 ajax的區別 在網絡上存在不少文章。我的現針對本身的狀況,來從新整理一份,便於本身記憶和理解。內容參考了網絡上的衆多文章。node

 

XMLHttpRequest

  瀏覽器經過XMLHttpRequest 對象進行 http 通訊。ios

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

 

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

 

  經常使用語法:ajax

  一個簡單的 http 請求編程

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

    

  一個稍微完整的 http 請求json

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字符串');

  這個是從網上找的。若是粗看官網提供的文檔,可能須要好久的時間才能明白究竟怎麼用。此處我先列出引用下。axios

JQuery ajax

  菜鳥教程:AJAX 是一種與服務器交換數據的技術,能夠在不從新載入整個頁面的狀況下更新網頁的一部分。後端

  基本語法:

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

  缺點:

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

  二、基於原生XHR開發,而XHR自己的架構不清晰 (我以爲此處應該是說官方給出的文檔架構不清晰。)

  三、JQuery整個項目太大,單純使用Ajax 卻要引入整個JQuery,很是的不合理(採起個性化打包的方案又不能享受CDN服務)

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

  五、配置和調用方法很是的混亂,並且基於事件的異步模型不友好。(配置和調用方法很是的混亂:想作封裝處理的時候,配置很差處理,須要作判斷,若是方法不公用 就每次調用都得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 的特徵:

  一、從瀏覽器中建立XMLHttpRequest

  二、支持 Promise API

  三、客戶端支持防止 CSRF

  四、提供了一些併發請求的接口(重要,方便了不少的操做)

  五、從 node.js 建立 http 請求

  六、攔截請求和響應

  七、轉換請求和響應數據

  八、取消請求

  九、自動轉換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 的優勢:

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

  二、更好更方便的寫法

 

  坦白說,上面的理由對我來講徹底沒有什麼說服力,由於不論是Jquery仍是Axios都已經幫咱們把xhr封裝的足夠好,使用起來也足夠方便,爲何咱們還要花費大力氣去學習fetch?

我認爲fetch的主要優點就是:

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

  二、基於標準 Promise 實現,支持 async / await

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

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

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

  

  最近在使用fetch的時候,也遇到了很多的問題:
fetch是一個低層次的API,你能夠把它考慮成原生的XHR,因此使用起來並非那麼舒服,須要進行封裝。

  例如:

  一、fetch 只對網絡請求報錯,對400,500都看成成功的請求,服務器返回400, 500 錯誤碼時並不會 reject,只有網絡錯誤這些致使請求不能完成時, fetch 纔會被 reject。須要封裝去處理。

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

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

  四、fetch 沒有辦法原生監測請求的進度,而 XHR 能夠。

  五、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)

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

    二、promise 自己是同步的,但它的成功的回調 .then 方法 是異步的。

    三、promise 的狀態是不可逆的

    四、then return 出去的值,會被後面的 then 接收,若是後面還跟着 then 的話,catch同理

    五、promise 無論返回什麼值,都會被包裝成一個promise 對象,即便這個返回值是error

    六、then 接收到的值,若是不是一個函數,會穿透到後面的 then

    七、promise 對象若是 resolve 或者 reject 的也是一個 promise 對象,那麼 promise 對象的狀態會由 resolve 或者 reject 的 promise 對象的狀態決定。


 

文章推薦:

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

併發和並行,異步與多線程區別:http://www.javashuo.com/article/p-xqexciwq-ca.html

相關文章
相關標籤/搜索