1. 程式人生 > >扒一扒 EventServiceProvider 源代碼

扒一扒 EventServiceProvider 源代碼

change 部分 get 資源 baidu load rec stat dst

Ajax用一句話來說就是無須刷新頁面即可從服務器取得數據。註意,雖然Ajax翻譯過來叫異步JavaScriptXML,但是獲得的數據不一定是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請求,使用XHRopen()方法,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.targetXHR對象,另外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

扒一扒 EventServiceProvider 源代碼