天天看點

扒一扒 EventServiceProvider 源代碼

Ajax

用一句話來說就是無須重新整理頁面即可從伺服器取得資料。注意,雖然

Ajax

翻譯過來叫異步

JavaScript

XML

,但是獲得的資料不一定是

XML

資料,現在伺服器端傳回的都是

JSON

格式的檔案。

完整的

Ajax

請求過程

Ajax

  1. 建立

    XMLHttpRequest

    執行個體
  2. 發出

    HTTP

    請求
  3. 接收伺服器傳回的資料
  4. 更新網頁資料

下面先看一個紅寶書上給出的發起

Ajax

請求的例子,

API

的用法在後面章節給出。

var xhr = new XMLHttpRequest();  // 建立XMLHttpRequest執行個體

xhr.onreadystatechange = function(){
  if (xhr.readyState == 4){   // 判斷請求響應過程階段,4 階段代表已接收到資料
    if (xhr.status >=200 && xhr.status < 300 || xhr.status == 304) {  // 校驗HTTP狀态碼
      console.log(xhr.responseText);   // 輸出響應的文本
    } else {
      console.error(xhr.status, xhr.statusText); // 列印其他HTTP狀态碼
    }
  }
};

xhr.open('get', 'example.txt', true); // 初始化xhr執行個體,或者說啟動請求
xhr.send(null);  // 設定HTTP請求攜帶參數,null為不帶參數
           

Ajax

請求過程詳解

1. 建立

XMLHttpRequest

從上面的的代碼可以看出,建立一個

XHR

執行個體方式為:

var xhr = new XMLHttpRequest();
           

2. 發出HTTP請求

執行個體建立好後,首先需要啟動一個

HTTP

請求,使用

XHR

open()

方法,

open

方法接受三個參數

XMLHttpRequest.open(method, url, isAsync)
// 例如
xhr.open('get', 'http://www.baidu.com', true)
           

第一個參數為

http

請求使用方法,如('get','post'等),第二是參數是請求的

url

, 第三個參數代表是否異步發送請求(可選)。調用

open()

方法後會啟動一個

http

請求,但它不會立即發送請求,處于待命狀态。需要注意的是:請求的

url

必須要跟請求源域(origin)同域,也就是說協定、域名、端口号要一緻,跨域請求要使用别的方法。接着調用

send()

方法就會發出這個

http

請求。

xhr.open('get', 'http://www.baidu.com', true)
xhr.send(null)
           

send()

方法接受一個參數,為

http

請求發送的資料(通常用于'post'方法),如果為

null

,表示不發送資料。至此,一個異步的

http

請求就發送到了伺服器。

3. 接收伺服器傳回的資料

3.1 發送同步請求

如果将

open

方法的第三個參數設為

false

,即為同步請求,當收到伺服器的響應後,相應的資料會自動填充到

XHR

對象的屬性中,主要包括以下四個:

  • responseText

    :作為響應主體被傳回的文本。
  • responseXML

    : 響應傳回的

    XML

    文檔,能接收到的前提是,響應的

    Content-Type

    字段的值為

    text/xml

    或者

    application/xml

  • status

    :

    HTTP

    狀态碼。
  • statusText

    HTTP

    狀态碼說明。

當用戶端收到以上資訊後,首先要判斷

HTTP

狀态碼來确認響應是否成功,狀态碼在200-300之間表示請求成功,同時304代表請求資源未被修改,可使用浏覽器本地緩存。如果成功就可以擷取響應封包主體中的資料了。

xhr.open('get', 'http://www.baidu.com', false)
xhr.send(null)

if (xhr.status >=200 && xhr.status < 300 || xhr.status == 304) {  // 校驗HTTP狀态碼
  console.log(xhr.responseText);   // 輸出響應的文本
} else {
  console.error(xhr.status, xhr.statusText); // 列印其他HTTP狀态碼
}
           

3.2 發送異步請求

open

true

,即為異步請求。那麼就需要一個事件來通知程式異步請求的結果是否傳回。

XHR

對象中的

readyState

屬性,表示請求/響應整個過程所處的階段,它有五個值分為對應五個階段:

  • 0:未初始化。未調用

    open()

    方法。
  • 1:啟動。已經調用

    open()

    方法,但未調用

    send()

  • 2:發送。已調用

    send()

    方法,但未收到響應。
  • 3: 接收。已經接收到部分響應資料。
  • 4:完成。已經接受到全部響應資料。

readyState

的值每變化一次,都會觸發一次

readStatechange

事件,我們定義一個事件處理函數

onreadStatechange()

,并監聽

readyState == 4

狀态,就可以得知響應資料已全部收到,并進行下一步操作。那麼就是文章開頭給出的代碼:

var xhr = new XMLHttpRequest();  // 建立XMLHttpRequest執行個體

xhr.onreadystatechange = function(){
  if (xhr.readyState == 4){   // 判斷請求響應過程階段,4 階段代表已接收到資料
    if (xhr.status >=200 && xhr.status < 300 || xhr.status == 304) {  // 校驗HTTP狀态碼
      console.log(xhr.responseText);   // 輸出響應的文本
    } else {
      console.error(xhr.status, xhr.statusText); // 列印其他HTTP狀态碼
    }
  }
};

xhr.open('get', 'example.txt', true); // 初始化xhr執行個體,或者說啟動請求
xhr.send(null);  // 設定HTTP請求攜帶參數,null為不帶參數
           

補充XHR中三個有用的事件

timeout

事件

當超出了設定時間還未收到響應,就會觸發

timeout

事件,進而調用

ontimeout

事件處理程式。同時

timeout

也是

XHR

的一個屬性,用于設定這個時間門檻值。下面是用法:

xhr.ontimeout = function() {
  alert('timeout!')
}

xhr.open('get', 'http://www.baidu.com', true)
xhr.timeout = 1000 // 時間門檻值設為1秒
xhr.send(null)
           

load

load

事件用于簡化對

readState

值的判斷,響應資料全部接收完畢後(也就是

readState == 4

)會觸發

load

事件,使用

onload

事件處理函數進行後續操作,

onload

會接收一個

event

對象,它的

target

屬性等于

XHR

對象,當然我們在定義這個事件處理函數時也可以不傳入這個參數,來看下面的用法:

var xhr = new XMLHttpRequest()
xhr.onload = function () {
  if(xhr.status >=200 && xhr.status < 300 || xhr.status == 304) {
    console.log(xhr.responseText);   // 輸出響應的文本
  } else {
    console.error(xhr.status, xhr.statusText); // 列印其他HTTP狀态碼
  }
}
xhr.open('get', 'http://www.baidu.com', true)
xhr.send(null)
           

這樣就不用去關心

readyState

值的變化情況了。當然如果想在特定

readyState

值上做一些邏輯處理,還是要用之前的方法。

progress

這個是很有用的一個事件,

progress

事件會在浏覽器接收資料期間周期觸發,代表整個請求過程的進度,它的事件處理程式

onprogress

接收一個

event

對象,

event.target

XHR

對象,另外

event

還有三個屬性:

  • lengthComputable

    :Boolean值,進度資訊是否可用。
  • position

    :已經接收到的位元組數。
  • totalSize

    :總共要接收的位元組數,被定義在響應封包的

    Content-Length

    字段中。

如果響應封包中有

Content-Length

字段,那麼我們就可以計算目前時刻響應資料的加載進度了,這也是之前看到的一個面試題。看下面的代碼:

xhr.onprogress = function(event) {
  if(event.lengthComputable) {
    console.log(`Received: ${(event.position/event.totalSize).toFixed(4)*100}%`);
  }
}
           

其他還有很多有用的API,如

FormData

表單序列化,

overrideMimeType()

重寫

XHR

響應的

MIME

類型等等,後面慢慢更新。

原文位址:https://segmentfault.com/a/1190000015668383

繼續閱讀