前端戰五渣:」啊!賈克斯?武器大師?Ajax!XMLHttpRequest「

啥都不說了,挺華爲就完事了,山姆大叔有點過度了,我相信華爲能挺過來javascript

如今該我了!

啊,賈克斯???如今從事前端的小夥伴不可能不知道這個,若是真不知道這個詞,那我以爲你還稱不上前端開發🙄css

此賈克斯非彼賈克斯,前端說的啊賈克斯是Asynchronous javaScript + XML的簡寫,Ajax在很大程度上讓前端發展加快了腳步,他的出現和使用,但是說是前端史上的里程碑html

Ajax橫空出世,打破了先後端交互的時候須要從新加載頁面,就是整頁刷新,咱們能夠經過Ajax技術直接在頁面不刷新的狀況下,發出請求,獲取返回數據,而後經過js操做Dom更改頁面內容。前端

也是Ajax出現了之後,才促成了日後的先後端分離,再也不是前端只負責切圖,只是給後端同窗提供模板,而後數據由後端同窗添加上。咱們前端今後也能夠再也不依賴後端同窗模板套數據了,咱們本身就能夠完成。java

那咱們是如何實現這個無刷新獲取數據呢,這就要基於一個對象了————XMLHttpRequestjquery

開打!開打!

Ajax說白了不是新技術,只是一種解決方案,跟jsonp差很少,是基於XMLHttpRequest對象的一個獲取後端數據的方案,那咱們來看看怎麼寫的吧(本文不涉及兼容ie等部分瀏覽器,走主流)ios

get請求

(() => {
  // 獲取頁面上須要發請求的按鈕
  let btn = document.querySelector('.getAjaxBtn'); 
  // 添加事件
  btn.addEventListener('click', createXHR)
  // 咱們ajax的主體函數
  function createXHR() {
    // new一個XMLHttpRequest實例
    var xhr = new XMLHttpRequest();
    // 第一步使用open方法,接收三個參數
    // 第一個參數是請求方法名(get,post等)
    // 第二個參數是須要請求的接口地址
    // 第三個參數是設置請求是不是異步,通常都是都是發送異步請求,同步請求可能會阻塞頁面
    // 咱們先來看同步請求
    xhr.open('get', '/api/get', false);
    // open方法只是設置參數,並不會發送請求
    // 而請求是由send()方法發送的,而且接收一個參數,就是須要發送到服務端的數據
    // 若是沒有須要發送到服務端的數據,必須傳入null,由於有些瀏覽器不準要這個參數
    xhr.send(null)
  }

})()
複製代碼

這樣寫的話,咱們就在一個按鈕上綁定了一個發送get請求的方法,只要咱們點擊這個按鈕,就會發送請求,那咱們來看看是什麼效果 面試

其實很簡單是否是,沒錯,這樣咱們確實就已經發送了一個get請求了,那咱們發送請求是爲了什麼呢,固然是爲了獲取到數據,那咱們看到接口已經返回了字符串'恭喜你,你發送了一個get請求,真棒!',那咱們怎麼能拿到這個數據呢,看下面ajax

拿到返回數據

其實咱們在收到服務端響應的時候,就已經拿到了數據,響應的數據會自動填充到XHR對象中,但咱們何時才能知道這個數據已經填充到XHR對象中呢??這個時候咱們就須要一個相似於監聽函數的事件————readystatechange事件,z這個事件當readystate狀態改變,就會執行一次。咱們還須要一個知道請求發送狀態的屬性————readystate,還有一個請求狀態碼屬性————statusjson

狀態碼就是200、404以及500這種的,在這就不細說了,主要說說readystate有什麼狀態:

  • 0: 未初始化。還沒有調用open()方法
  • 1: 啓動。已經調用open()方法,但還沒有調用send()方法
  • 2:發送。已經調用send()方法,但還沒有接收到響應
  • 3:接收。已經接收到部分相應數據
  • 4:完成。已經接收到所有響應數據,並且已經能夠在客戶端使用了

看了一下這接個狀態,好像咱們如今須要的是4這個狀態,接收到了所有的數據,而後咱們再作一個邏輯處理,上面的請求咱們是同步請求,如今咱們改改裝一下

(() => {
  // 獲取頁面上須要發請求的按鈕
  let btn = document.querySelector('.getAjaxBtn'); 
  // 添加事件
  btn.addEventListener('click', createXHR)
  // 咱們ajax的主體函數
  function createXHR() {
    // new一個XMLHttpRequest實例
    var xhr = new XMLHttpRequest();
    // 第一步使用open方法,接收三個參數
    // 第一個參數是請求方法名(get,post等)
    // 第二個參數是須要請求的接口地址
    // 第三個參數是設置請求是不是異步,通常都是都是發送異步請求,同步請求可能會阻塞頁面
    // 咱們先來看同步請求
    xhr.open('get', '/api/get', true);
    // 咱們爲xhr添加一個readyState值改變就執行的監聽事件
    // 這個事件還必須寫在send()方法前面
    xhr.onreadystatechange = function () {
      // 當readyState值爲4就是接收到了所有返回數據,而且http狀態碼是200多的成功,或者是304的緩存,這時候就判斷已是成功拿到了應該返回的數據
      if (xhr.readyState === 4 ) {
        if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304 ) {
          // 輸出數據。responseText是做爲響應主體被返回的文本
          alert(xhr.responseText)
        } else {
          alert('請求不成功')
        }
      } 
    }
    // open方法只是設置參數,並不會發送請求
    // 而請求是由send()方法發送的,而且接收一個參數,就是須要發送到服務端的數據
    // 若是沒有須要發送到服務端的數據,必須傳入null,由於有些瀏覽器不準要這個參數
    xhr.send(null)
  }

})()
複製代碼

這樣咱們就成功的拿到了返回的數據而且彈出來了,咱們不只拿到數據能夠彈出,咱們就能夠進行一些更厲害的邏輯處理或者改變頁面內容了。

固然了,也許你get請求的時候須要發送一些數據給服務端,多是什麼頁碼或者頁面須要多少條數據等,咱們這個時候只要在open()方法中傳入的url上面拼上就好了,相似/api/get?pageNum=1&pageSize=20這樣的url。

咱們寫的服務端就是返回請求中的數據,咱們也能看到,咱們也收到了返回來的數據了

post請求

post請求,咱們應該接觸過form的表單提交,咱們post請求傳輸的數據必須是通過encodeURIComponent轉碼的,並且當咱們接收到一個json對象,咱們須要將他進行轉換

(() => {
  let btn = document.querySelector('.getAjaxBtn'); 
  btn.addEventListener('click', createXHR);
  // 咱們須要轉換的數據,真實場景咱們應該是傳進來的,或者是獲取到的用戶輸入的數據
  let data = {
    method: 'post',
    a: 'a',
    b: 123,
  }
  function createXHR() {
    var xhr = new XMLHttpRequest();
    xhr.open('post', '/api/post', true);
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4 ) {
        if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304 ) {
          alert(xhr.responseText)
        } else {
          alert('請求不成功')
        }
      } 
    }
    // 模仿表單提交,設置content-type,咱們須要從新設置請求頭,讓服務端能知道咱們傳的是個什麼數據
    xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    // send()方法須要傳入的數據應該通過處理
    xhr.send(transformData(data))
  }
  // 處理傳入json對象轉換格式
  /** * 例如這個樣的json * { method: 'post', a: 'a', b: 123, } */
  // 轉換格式爲
  // method=post&a=a&b=123
  // 這樣
  function transformData(data) {
    let newData = [];
    for (let key in data) {
      newData.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key]))
    }
    return newData.join('&')
  }

})()
複製代碼

上面就是咱們進行的post請求,咱們能看到咱們發送了一了個Form Data,而後服務端拿到了這個數據,而且咱們拿到了會返回來的數據,也就是咱們發送給服務端的數據

還有誰!

固然除了我上面說到的一些屬性和方法,XHR還有不少我沒有介紹到的方法和屬性,這裏就說一下幾個經常使用的吧

  • XMLHttpRequest.timeout: 這個就是能夠設置請求超時,設置一個時間,單位爲毫秒,若是請求時間超過設置時間,直接拋出異常
  • XMLHttpRequest.withCredentials: 這個屬性是看咱們需不須要發送cookie的,由於若是是跨域請求,通常請求是不會帶上cookie,須要咱們手動設置這個屬性
  • XMLHttpRequest.abort(): 這個方法咱們用來終止請求,固然是在請求發送並無返回的時候
  • XMLHttpRequest.setRequestHeader(): 這個咱們剛纔有用到過,就是設置請求頭,更改一些咱們須要的設置

把他們也算上!

若是咱們這麼寫,咱們會發現很麻煩,並且若是咱們沒有考慮周全,這個請求方法會很糟糕,隱藏一些未知問題

技術,向來都是爲了提升效率,或者也能夠說是爲懶人研究的

如今已經有很好的成熟的開源庫替咱們封裝好了ajax請求方法,例如「尚能飯否的jQuery」以及隨着框架模塊大放異彩的「Axios」,他們的使用方法相對簡單不少,也不用咱們本身去處理一些邏輯問題,邊界問題。

jQuery & Axios

咱們來看看這兩個是多麼簡單實現的

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
  <title>Ajax</title>
</head>
<body>
  <button class="postAxiosBtn">發送axios post請求</button>
  <button class="getAxiosBtn">發送axios get請求</button>
  <button class="postJqueryBtn">發送jQuery post請求</button>
  <button class="getJqueryBtn">發送jQuery get</button>
  <script> var postAxiosBtn = $('.postAxiosBtn'), getAxiosBtn = $('.getAxiosBtn'), postJqueryBtn = $('.postJqueryBtn'), getJqueryBtn = $('.getJqueryBtn'); postAxiosBtn.click(() => { axios.post('/api/post', { data: { method: 'post', a: 'a', b: 123, } }).then(res => { console.log(res) }) }) getAxiosBtn.click(() => { axios.get('/api/get', { params: { pageNum: 1, pageSize: 20 } }).then(res => { console.log(res) }) }) postJqueryBtn.click(() => { $.post('/api/post', {method: 'post', a: 'a', b: 123}, function (data, status) { console.log(data) console.log(status) }) }) getJqueryBtn.click(() => { $.get('/api/get', {pageNum: 1, pageSize: 20}, function (data, status) { console.log(data) console.log(status) }) }) </script>
</body>
</html>
複製代碼

封裝庫使用起來就是這麼簡單!!!

哼,一個能打的都沒有!

fetch

想來你們也都知道fetch這個api了,js新出的一個api,對標的就是XMLHttpRequest,可是相比於XMLHttpRequest,fetch的使用很人性化了,並且自帶promise語法,咱們不用再用什麼回調的方法了,可是fetch再去跟axios這種封裝XMLHttpRequest的庫來講,使用方法上還有有很大的差距吧。

但我相信之後封裝fetch這種的庫會愈來愈多的,如今雖然有,可是我感受用的人尚未要使用axios那種程度😜

總結

如今已經不多會用到純手寫原生Ajax了,都會用已經寫好的封裝庫了,可是面試的時候不乏也會遇到讓你手寫的,這就很頭疼了

尤大的回答不無道理,可是能說上來或者手寫原生Ajax的人,絕對是對只是有着一種執着

知其然也得知其因此然,寫僞代碼我感受也是說的過去的,起碼對大的思路要了解,一些api接不住無所謂,js、css那麼多屬性,方法,要是都記下來確定是不可能的,可是仍是能知道有這個東西的存在,查的時候也好查,是否是🤠


我是前端戰五渣,一個前端界的小學生。

相關文章
相關標籤/搜索