Ajax,jQuery ajax,axios和fetch介紹、區別以及優缺點

曲小強發表於2019-08-22

引言

前端的發展可以說是一個快速崛起的歷程了,不斷的進化,不斷的出現新的Api,新的功能,前端這個領域真的是一個發展飛快的領域,你前一天剛學會XXX的的運用,後一天某某某就革新了一項新的技術,你在感嘆學不動的同時,不得不繼續學習。扯遠了,回到我們今天的主題。。。

三年前入職的時候還是一個只會使用AjaxJquery Ajax的菜鳥,由於早期Jquery不支援大檔案請求的問題,可以原生的XHR解決。

以下篇幅較長,建議收藏了慢慢收看。在這裡學到的肯定會對你有所幫助

介紹

「Ajax」:

全稱Asynchronous JavaScript and XML(非同步的 JavaScript 和 XML)最早出現的傳送後端請求技術,隸屬於原始js中,核心使用XMLHttpRequest物件,多個請求之間如果有先後關係的話,就會出現回撥地獄。

「Jquery Ajax」:

是 jQuery 底層 AJAX 實現。簡單易用的高層實現見 $.get, $.post 等。$.ajax() 返回其建立的 XMLHttpRequest 物件。大多數情況下你無需直接操作該函式,除非你需要操作不常用的選項,以獲得更多的靈活性。jQuery ajax - ajax() 方法

「Axios」:

axios不是原生JS的,需要進行安裝,它不但可以在客戶端使用,也可以在nodejs端使用。Axios也可以在請求和響應階段進行攔截。同樣也是基於Promise物件的。特性:從瀏覽器中建立 XMLHttpRequests、從 node.js 建立 http 請求、支援 Promise API、攔截請求和響應等。Axios 中文文件傳送門

「Fetch」:

Fetch 提供了對 RequestResponse (以及其他與網路請求有關的)物件的通用定義。使之今後可以被使用到更多地應用場景中:無論是service workersCache API、又或者是其他處理請求和響應的方式,甚至是任何一種需要你自己在程式中生成響應的方式。Fetch號稱是AJAX的替代品,是在ES6出現的,使用了ES6中的Promise物件。Fetch是基於promise設計的。Fetch的程式碼結構比起ajax簡單多了,引數有點像jQuery ajax。但是,一定記住fetch不是ajax的進一步封裝,而是原生js。Fetch函式就是原生js,沒有使用XMLHttpRequest物件。

細談

詳細的描述一下Ajax,jQuery ajax,axios和fetch區別,讓我們繼續往下研究。

AJAX = 非同步 JavaScript 和 XML。

AJAX 是一種用於建立快速動態網頁的技術。

通過在後臺與伺服器進行少量資料交換,AJAX 可以使網頁實現非同步更新。這意味著可以在不重新載入整個網頁的情況下,對網頁的某部分進行更新。

AJAX 工作原理

一、Ajax

XMLHttpRequest 讓傳送一個HTTP請求變得非常容易。你只需要簡單的建立一個請求物件例項,開啟一個URL,然後傳送這個請求。當傳輸完畢後,結果的HTTP狀態以及返回的響應內容也可以從請求物件中獲取。簡單的來敘述一下這個過程,往下看:

function reqListener () {
  console.log(this.responseText);
}

var oReq = new XMLHttpRequest();
oReq.onload = reqListener;
oReq.open("get", "newFile.txt", true);
oReq.send();
1-1 請求型別

通過XMLHttpRequest生成的請求可以有兩種方式來獲取資料,非同步模式同步模式。請求的型別是由這個XMLHttpRequest物件的open()方法的第三個引數async的值決定的。如果該引數的值為false,則該XMLHttpRequest請求以同步模式進行,否則該過程將以非同步模式完成。

注意:由於對使用者體驗的糟糕效果,從Gecko 30.0(Firefox 30.0 / Thunderbird 30.0 / SeaMonkey 2.27)版本開始,在主執行緒上的同步請求已經被棄用

1-2 處理響應

W3C規範定義了XMLHttpRequest物件的幾種型別的響應屬性。這些屬性告訴客戶端關於XMLHttpRequest返回狀態的重要資訊。一些處理非文字返回型別的用例可能包含一些下面章節描述的操作和分析。

1-2-1、分析並操作 responseXML屬性

如果你使用 XMLHttpRequest 來獲得一個遠端的 XML 文件的內容,responseXML 屬性將會是一個由 XML 文件解析而來的 DOM 物件,這很難被操作和分析。這裡有五種主要的分析 XML 文件的方式

  • 1.使用 XPath 定位到文件的指定部分。
  • 2.使用 JXON 將其轉換成 JavaScript 物件樹。
  • 3.手工的 解析和序列化 XML 為字串或物件。
  • 4.使用 XMLSerializer 把 DOM 樹序列化成字串或檔案。
  • 5.如果你預先知道 XML 文件的內容,你可以使用 RegExp。如果你用 RegExp 掃描時受到換行符的影響,你也許想要刪除所有的換行符。然而,這種方法是"最後手段",因為如果 XML 程式碼發生輕微變化,該方法將可能失敗。

1-2-2、解析和操作包含 HTML 文件的 responseText 屬性

如果使用 XMLHttpRequest 從遠端獲取一個 HTML 頁面,則所有 HTML 標記會以字串的形式存放在responseText 屬性裡,這樣就使得操作和解析這些標記變得困難。解析這些HTML標記主要有三種方式

  • 1.使用 XMLHttpRequest.responseXML 屬性。
  • 2.將內容通過 fragment.body.innerHTML 注入到一個 文件片段 中,並遍歷 DOM 中的片段。
  • 3.如果你預先知道 HTML 文件的內容,你可以使用 RegExp 。如果你用 RegExp 掃描時受到換行符的影響,你也許想要刪除所有的換行符。 然而,這種方法是"最後手段",因為如果 HTML 程式碼發生輕微變化,該方法將可能失敗。
1-3 處理二進位制資料

儘管 XMLHttpRequest 一般用來傳送和接收文字資料,但其實也可以傳送和接受二進位制內容。有許多經過良好測試的方法來強制使用 XMLHttpRequest 傳送二進位制資料。利用 XMLHttpRequest.overrideMimeType() 方法是一個解決方案,雖然它並不是一個標準方法。

var oReq = new XMLHttpRequest();
oReq.open("GET", url, true);
// retrieve data unprocessed as a binary string
oReq.overrideMimeType("text/plain; charset=x-user-defined");

在 XMLHttpRequest Level 2 規範中新加入了 responseType 屬性 ,使得傳送和接收二進位制資料變得更加容易。

var oReq = new XMLHttpRequest();

oReq.onload = function(e) {
  var arraybuffer = xhr.response; // not responseText
  /* ... */
}
oReq.open("GET", url, true);
oReq.responseType = "arraybuffer";
oReq.send();
1-4 監測進度

XMLHttpRequest 提供了各種在請求被處理期間發生的事件以供監聽。這包括定期進度通知、 錯誤通知,等等。

支援 DOM 的 progress 事件監測之於 XMLHttpRequest 傳輸,遵循 Web API 進度事件規範 : 這些事件實現了 ProgressEvent 介面。

1-5 提交表單和上傳檔案

XMLHttpRequest 的例項有兩種方式提交表單:

  • 使用 AJAX
  • 使用 FormData API

第二種方式( 使用 FormData API )是最簡單最快捷的,但是缺點是被收集的資料無法使用JSON.stringify()轉換為一個 JSON字串。
第一種方式反而是最複雜的但也是最靈活和最強大。

請求方式這裡不做太多贅述,一個傳送門,有興趣的小夥伴可以自己去查閱一下。

二、Jquery Ajax

$.ajax({
  url: "/api/getWeather",
  data: {
    zipcode: 97201
  },
  success: function( result ) {
    $( "#weather-temp" ).html( "<strong>" + result + "</strong> degrees" );
  }
});

傳統 Ajax 指的是 XMLHttpRequest(XHR), 最早出現的傳送後端請求技術,隸屬於原始js中,核心使用XMLHttpRequest物件,多個請求之間如果有先後關係的話,就會出現回撥地獄。Jquery Ajax的出現是對原生XHR的封裝,除此以外還增添了對JSONP的支援,Jquery Ajax經過多年的更新維護,真的已經是非常的方便了,但是隨著react,vue,angular新一代框架的興起,以及ES規範的完善,更多API的更新,它逐漸暴露了自己的不足:

  • 1.本身是針對MVC的程式設計,不符合現在前端MVVM的浪潮
  • 2.基於原生的XHR開發,XHR本身的架構不清晰,已經有了fetch的替代方案
  • 3.JQuery整個專案太大,單純使用ajax卻要引入整個JQuery非常的不合理(採取個性化打包的方案又不能享受CDN服務)
  • 4.不符合關注分離(Separation of Concerns)的原則
  • 5.配置和呼叫方式非常混亂,而且基於事件的非同步模型不友好

預設情況下,Ajax 請求使用 GET 方法。如果要使用 POST 方法,可以設定 type 引數值。這個選項也會影響 data 選項中的內容如何傳送到伺服器。

data 選項既可以包含一個查詢字串,比如 key1=value1&key2=value2 ,也可以是一個對映,比如 {key1: 'value1', key2: 'value2'} 。如果使用了後者的形式,則資料再傳送器會被轉換成查詢字串。這個處理過程也可以通過設定 processData 選項為 false 來回避。如果我們希望傳送一個 XML 物件給伺服器時,這種處理可能並不合適。並且在這種情況下,我們也應當改變 contentType 選項的值,用其他合適的 MIME 型別來取代預設的 application/x-www-form-urlencoded

var list = {}; 
$.ajax({
    //請求方式 POST || GET
    type : "POST", 
    //請求的媒體型別
    contentType: "application/json;charset=UTF-8",
    //請求地址
    url : "http://127.0.0.1/xxxx/",
    //資料,json字串
    data : JSON.stringify(list),
    //請求成功
    success : function(result) {
        console.log(result);
    },
    //請求失敗,包含具體的錯誤資訊
    error : function(e){
        console.log(e.status);
        console.log(e.responseText);
    }
});

下面的表格列出了 jQuery AJAX 方法:

| 方法 | 描述 |
| $.ajax() | 執行非同步 AJAX 請求 |
| $.ajaxPrefilter() | 在每個請求傳送之前且被 $.ajax() 處理之前,處理自定義 Ajax 選項或修改已存在選項 |
| $.ajaxSetup() | 為將來的 AJAX 請求設定預設值 |
| $.ajaxTransport() | 建立處理 Ajax 資料實際傳送的物件 |
| $.get() | 使用 AJAX 的 HTTP GET 請求從伺服器載入資料 |
| $.getJSON() | 使用 HTTP GET 請求從伺服器載入 JSON 編碼的資料 |
| $.getScript() | 使用 AJAX 的 HTTP GET 請求從伺服器載入並執行 JavaScript |
| $.param() | 建立陣列或物件的序列化表示形式(可用於 AJAX 請求的 URL 查詢字串) |
| $.post() | 使用 AJAX 的 HTTP POST 請求從伺服器載入資料 |
| ajaxComplete() | 規定 AJAX 請求完成時執行的函式 |
| ajaxError() | 規定 AJAX 請求失敗時執行的函式 |
| ajaxSend() | 規定 AJAX 請求傳送之前執行的函式 |
| ajaxStart() | 規定第一個 AJAX 請求開始時執行的函式 |
| ajaxStop() | 規定所有的 AJAX 請求完成時執行的函式 |
| ajaxSuccess() | 規定 AJAX 請求成功完成時執行的函式 |
| load() | 從伺服器載入資料,並把返回的資料放置到指定的元素中 |
| serialize() | 編碼表單元素集為字串以便提交 |
| serializeArray() | 編碼表單元素集為 namesvalues 的陣列 |

對於Jquery Ajax來說我是特別的喜歡,只是人在進步,新的知識中終歸會替代那些舊的。

總結: 這裡引用海賊王白鬍子說的一句話,如圖,載入不出來就別看了~~

三、Axios

先來看看官網的案例:

執行 GET 請求

// 為給定 ID 的 user 建立請求
axios.get('/user?ID=12345')
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

// 上面的請求也可以這樣做
axios.get('/user', {
    params: {
      ID: 12345
    }
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

執行 POST 請求

axios.post('/user', {
    firstName: 'Fred',
    lastName: 'Flintstone'
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

執行多個併發請求

function getUserAccount() {
  return axios.get('/user/12345');
}

function getUserPermissions() {
  return axios.get('/user/12345/permissions');
}

axios.all([getUserAccount(), getUserPermissions()])
  .then(axios.spread(function (acct, perms) {
    // 兩個請求現在都執行完成
  }));

Vue2.0之後,尤雨溪推薦大家用axios替換JQuery ajax`,未來App的趨勢是輕量化和細化,能解決問題的應用就是好應用,想必讓Axios進入了很多人的目光中。Axios本質上也是對原生XHR的封裝,只不過它是Promise的實現版本,可以用在瀏覽器和 node.js 中,符合最新的ES規範,從它的官網上可以看到它有以下幾條特性:

  • 從瀏覽器中建立 XMLHttpRequests
  • 從 node.js 建立 http 請求
  • 支援 Promise API
  • 攔截請求和響應
  • 轉換請求資料和響應資料
  • 取消請求
  • 自動轉換 JSON 資料
  • 客戶端支援防禦 XSRF

XSRFCross Site Request Forgery, 跨站域請求偽造)也稱 XSRF, 是一種網路的攻擊方式,它在 2007 年曾被列為網際網路 20 大安全隱患之一。其他安全隱患,比如 SQL 指令碼注入,跨站域指令碼攻擊等在近年來已經逐漸為眾人熟知,很多網站也都針對他們進行了防禦。然而,對於大多數人來說,CSRF 卻依然是一個陌生的概念。即便是大名鼎鼎的 Gmail, 在 2007 年底也存在著 CSRF 漏洞,從而被黑客攻擊而使 Gmail 的使用者造成巨大的損失。客戶端支援防禦 XSRF,是怎麼做到的呢,就是讓你的每個請求都帶一個從cookie中拿到的key, 根據瀏覽器同源策略,假冒的網站是拿不到你cookie中得key的,這樣,後臺就可以輕鬆辨別出這個請求是否是使用者在假冒網站上的誤導輸入,從而採取正確的策略。

axios建立請求時可以用的配置選項。只有 url 是必需的。如果沒有指定 method,請求將預設使用 get 方法。請求配置傳送門

Axios既提供了併發的封裝,體積也較小,也沒有下文會提到的fetch的各種問題,當之無愧是現在最應該選用的請求的方式。

四、Fetch

Fetch 提供了對 RequestResponse (以及其他與網路請求有關的)物件的通用定義。
Fetch 是一個現代的概念, 等同於 XMLHttpRequest。它提供了許多與XMLHttpRequest相同的功能,但被設計成更具可擴充套件性和高效性。

Fetch API 提供了一個 JavaScript介面,用於訪問和操縱HTTP管道的部分,例如請求和響應。它還提供了一個全域性 fetch()方法,該方法提供了一種簡單,合理的方式來跨網路非同步獲取資源。

請注意,fetch規範與jQuery.ajax()主要有兩種方式的不同,牢記:

  • 當接收到一個代表錯誤的 HTTP 狀態碼時,從 fetch()返回的 Promise 不會被標記為 reject, 即使該 HTTP 響應的狀態碼是 404500。相反,它會將 Promise 狀態標記為 resolve但是會將 resolve 的返回值的 ok 屬性設定為 false ),僅當網路故障時或請求被阻止時,才會標記為 reject
  • 預設情況下,fetch 不會從服務端傳送或接收任何 cookies, 如果站點依賴於使用者 session,則會導致未經認證的請求(要傳送 cookies,必須設定 credentials 選項)。自從2017年8月25日後,預設的credentials政策變更為same-originFirefox也在61.0b13中改變預設值

一個基本的 fetch請求設定起來很簡單。看看下面的程式碼:

fetch('http://example.com/movies.json')
  .then(function(response) {
    return response.json();
  })
  .then(function(myJson) {
    console.log(myJson);
  });

這裡我們通過網路獲取一個JSON檔案並將其列印到控制檯。最簡單的用法是隻提供一個引數用來指明想fetch()到的資源路徑,然後返回一個包含響應結果的promise(一個 Response 物件)

當然它只是一個 HTTP 響應,而不是真的JSON。為了獲取JSON的內容,我們需要使用 json()方法(在Bodymixin 中定義,被 Request 和 Response 物件實現)。

fetch() 接受第二個可選引數,一個可以控制不同配置的 init 物件:

// Example POST method implementation:

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
    credentials: 'same-origin', // include, same-origin, *omit
    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的優點:

  • 1.語法簡潔,更加語義化
  • 2.基於標準 Promise 實現,支援 async/await
  • 3.同構方便,使用 isomorphic-fetch
  • 4.更加底層,提供的API豐富(request, response)
  • 5.脫離了XHR,是ES規範裡新的實現方式

fetch在前端的應用上有一項xhr怎麼也比不上的能力:跨域的處理

我們都知道因為同源策略的問題,瀏覽器的請求是可能隨便跨域的——一定要有跨域頭或者藉助JSONP,但是,fetch中可以設定mode為"no-cors"(不跨域),如下所示:

fetch('/users.json', {
    method: 'post', 
    mode: 'no-cors',
    data: {}
}).then(function() { /* handle response */ });

這樣之後我們會得到一個type為“opaque”的返回。需要指出的是,這個請求是真正抵達過後臺的,所以我們可以使用這種方法來進行資訊上報,在我們之前的image.src方法中多出了一種選擇,另外,我們在network中可以看到這個請求後臺設定跨域頭之後的實際返回,有助於我們提前除錯介面(當然,通過chrome外掛我們也可以做的到)。

參考資料Fetch_API

參考資料MDC AJAX introduction

參考來源於MDN

相關文章