国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

你不知道的 XMLHttpRequest

ckllj / 2918人閱讀

摘要:默認參數為空字符串密碼,可選參數,用于授權。默認參數為空字符串備注如果不是有效的方法或地址不能被成功解析,將會拋出異常如果請求方法不區分大小寫為或將會拋出異常重寫由服務器返回的類型。

本文詳細介紹了 XMLHttpRequest 相關知識,涉及內容:

AJAX、XMLHTTP、XMLHttpRequest詳解、XMLHttpRequest Level 1、Level 2 詳解

XHR 上傳、下載數據、XHR 流式傳輸、XHR 定時輪詢和長輪詢區別與優缺點、XMLHttpRequest 庫 (Mock.js、Zone.js、Oboe.js、fetch.js)

XMLHttpRequest 常用代碼片段:

ArrayBuffer 對象轉字符串

字符串轉 ArrayBuffer 對象

創建 XHR 對象

sendAsBinary() polyfill

獲取 XMLHttpRequest 響應體

獲取 responseURL

驗證請求是否成功

解析查詢參數為Map對象

XHR 下載圖片

XHR 上傳圖片

XHR 上傳進度條

分析 AJAX 請求狀態為 0、GET請求方式為什么不能通過send() 方法發送請求體、簡單請求和預請求、XMLHttpRequest對象垃圾回收機制、Get與Post請求區別、如何避免重復發送請求、AJAX 站點 SEO 優化等問題。

AJAX AJAX 定義

AJAX即“Asynchronous JavaScript and XML”(異步的JavaScript與XML技術),指的是一套綜合了多項技術的瀏覽器端網頁開發技術。Ajax的概念由杰西·詹姆士·賈瑞特所提出。

傳統的Web應用允許用戶端填寫表單(form),當提交表單時就向網頁服務器發送一個請求。服務器接收并處理傳來的表單,然后送回一個新的網頁,但這個做法浪費了許多帶寬,因為在前后兩個頁面中的大部分HTML碼往往是相同的。由于每次應用的溝通都需要向服務器發送請求,應用的回應時間依賴于服務器的回應時間。這導致了用戶界面的回應比本機應用慢得多。

與此不同,AJAX應用可以僅向服務器發送并取回必須的數據,并在客戶端采用JavaScript處理來自服務器的回應。因為在服務器和瀏覽器之間交換的數據大量減少(大約只有原來的5%)[來源請求],服務器回應更快了。同時,很多的處理工作可以在發出請求的客戶端機器上完成,因此Web服務器的負荷也減少了。

類似于DHTML或LAMP,AJAX不是指一種單一的技術,而是有機地利用了一系列相關的技術。雖然其名稱包含XML,但實際上數據格式可以由JSON代替,進一步減少數據量,形成所謂的AJAJ。而客戶端與服務器也并不需要異步。一些基于AJAX的“派生/合成”式(derivative/composite)的技術也正在出現,如AFLAX。 —— 維基百科

AJAX 應用

運用XHTML+CSS來表達信息;

運用JavaScript操作DOM(Document Object Model)來運行動態效果;

運用XML和XSLT操作數據

運用XMLHttpRequest或新的Fetch API與網頁服務器進行異步數據交換;

注意:AJAX與Flash、Silverlight和Java Applet等RIA技術是有區分的。

AJAX 兼容性

JavaScript 編程的最大問題來自不同的瀏覽器對各種技術和標準的支持。

XmlHttpRequest 對象在不同瀏覽器中不同的創建方法,以下是跨瀏覽器的通用方法:

// Provide the XMLHttpRequest class for IE 5.x-6.x:
// Other browsers (including IE 7.x-8.x) ignore this
//   when XMLHttpRequest is predefined
var xmlHttp;
if (typeof XMLHttpRequest != "undefined") {
    xmlHttp = new XMLHttpRequest();
} else if (window.ActiveXObject) {
    var aVersions = ["Msxml2.XMLHttp.5.0", "Msxml2.XMLHttp.4.0", 
        "Msxml2.XMLHttp.3.0", "Msxml2.XMLHttp", "Microsoft.XMLHttp"];
    for (var i = 0; i < aVersions.length; i++) {
        try {
            xmlHttp = new ActiveXObject(aVersions[i]);
            break;
        } catch (e) {}
    }
}

詳細信息請參考 - Can I use XMLHttpRequest

AJAX/HTTP 庫對比
Support Features
All Browsers Chrome & Firefox1 Node Concise Syntax Promises Native2 Single Purpose3 Formal Specification
XMLHttpRequest ? ? ? ? ?
Node HTTP ? ? ? ?
fetch() ? ? ? ? ? ?
Fetch polyfill ? ? ? ? ? ?
node-fetch ? ? ? ? ?
isomorphic-fetch ? ? ? ? ? ? ?
superagent ? ? ? ? ?
axios ? ? ? ? ? ?
request ? ? ?
jQuery ? ? ?
reqwest ? ? ? ? ? ?

1 Chrome & Firefox are listed separately because they support fetch(): caniuse.com/fetch
2 Native: Meaning you can just use it - no need to include a library.
3 Single Purpose: Meaning this library or technology is ONLY used for AJAX / HTTP communication, nothing else.

詳細信息請參考 - AJAX/HTTP Library Comparison

XMLHTTP XMLHTTP 定義

XMLHTTP 是一組API函數集,可被JavaScript、JScript、VBScript以及其它web瀏覽器內嵌的腳本語言調用,通過HTTP在瀏覽器和web服務器之間收發XML或其它數據。XMLHTTP最大的好處在于可以動態地更新網頁,它無需重新從服務器讀取整個網頁,也不需要安裝額外的插件。該技術被許多網站使用,以實現快速響應的動態網頁應用。例如:Google的Gmail服務、Google Suggest動態查找界面以及Google Map地理信息服務。

XMLHTTP是AJAX網頁開發技術的重要組成部分。除XML之外,XMLHTTP還能用于獲取其它格式的數據,如JSON或者甚至純文本。—— 維基百科

XMLHTTP 背景知識

XMLHTTP最初是由微軟公司發明的,在Internet Explorer?5.0中用作ActiveX對象,可通過JavaScript、VBScript或其它瀏覽器支持的腳本語言訪問。Mozilla的開發人員后來在Mozilla 1.0中實現了一個兼容的版本。之后蘋果電腦公司在Safari?1.2中開始支持XMLHTTP,而Opera從8.0版開始也宣布支持XMLHTTP。

大多數使用了XMLHTTP的設計良好的網頁,會使用簡單的JavaScript函數,將不同瀏覽器之間調用XMLHTTP的差異性屏蔽,該函數會自動檢測瀏覽器版本并隱藏不同環境的差異。

在DOM?3(文檔對象模型 Level 3)的讀取和保存規范(Load and Save Specification)中也有類似的功能,它已經成為W3C推薦的方法。截止2011年,大多數瀏覽器已經支持。—— 維基百科

XMLHTTP 實現

ActiveXObject

XMLHttpRequest

什么是 ActiveX 控件

Microsoft ActiveX 控件是由軟件提供商開發的可重用的軟件組件。使用 ActiveX 控件,可以很快地在網址、臺式應用程序、以及開發工具中加入特殊的功能。例如,StockTicker 控件可以用來在網頁上即時地加入活動信息,動畫控件可用來向網頁中加入動畫特性。

ActiveXObject 對象

JavaScript 中 ActiveXObject 對象是啟用并返回 Automation 對象的引用。

ActiveXObject 語法

newObj = new ActiveXObject(servername.typename[, location])

參數:

newObj

必選 - ActiveXObject?分配到的變量名稱

servername

必選 - 提供對象的應用程序名稱

typename

必選 - 要創建的對象的類型或類

location

可選 - 要再其中創建對象的網絡服務器的名稱

ActiveXObject 使用

// 在IE5.x和IE6下創建xmlHttp對象
// servername - MSXML2
// typename - XMLHTTP.3.0
var xmlHttp = new ActiveXObject("MSXML2.XMLHTTP.3.0");
xmlHttp.open("GET", "http://localhost/books.xml", false);  
xmlHttp.send();  

詳細信息可以參考 - msdn - JavaScript 對象 - ActiveXObject 對象.aspx)

XMLHttpRequest

XMLHttpRequest 是一個API, 它為客戶端提供了在客戶端和服務器之間傳輸數據的功能。它提供了一個通過 URL 來獲取數據的簡單方式,并且不會使整個頁面刷新。這使得網頁只更新一部分頁面而不會打擾到用戶。XMLHttpRequest 在?AJAX?中被大量使用。

XMLHttpRequest 是一個?JavaScript?對象,它最初由微軟設計,隨后被 Mozilla、Apple 和 Google采納. 如今,該對象已經被?W3C組織標準化. 通過它,你可以很容易的取回一個URL上的資源數據. 盡管名字里有XML, 但?XMLHttpRequest?可以取回所有類型的數據資源,并不局限于XML。 而且除了HTTP?,它還支持file?和?ftp?協議。

XMLHttpRequest 語法

var req = new XMLHttpRequest();

XMLHttpRequest 使用

var xhr = new XMLHttpRequest(); // 創建xhr對象
xhr.open( method, url );
xhr.onreadystatechange = function () { ... };
xhr.setRequestHeader( ..., ... );
xhr.send( optionalEncodedData );
XMLHttpRequest 詳解 構造函數

用于初始化一個 XMLHttpRequest 對象,必須在所有其它方法被調用前調用構造函數。使用示例如下:

var req = new XMLHttpRequest();
屬性

onreadystatechange: Function - 當 readyState 屬性改變時會調用它。

readyState: unsigned short - 用于表示請求的五種狀態:

狀態 描述
0 UNSENT (未打開) 表示已創建 XHR 對象,open() 方法還未被調用
1 OPENED (未發送) open() 方法已被成功調用,send() 方法還未被調用
2 HEADERS_RECEIVED (已獲取響應頭) send() 方法已經被調用,響應頭和響應狀態已經返回
3 LOADING (正在下載響應體) 響應體下載中,responseText中已經獲取了部分數據
4 DONE (請求完成) 整個請求過程已經完畢

response: varies - 響應體的類型由 responseType 來指定,可以是 ArrayBuffer、Blob、Document、JSON,或者是字符串。如果請求未完成或失敗,則該值為 null。

response: varies - 響應體的類型由 responseType 來指定,可以是 ArrayBuffer、Blob、Document、JSON,或者是字符串。如果請求未完成或失敗,則該值為 null。

responseText: DOMString - 此請求的響應為文本,或者當請求未成功或還是未發送時未 null (只讀)

responseType: XMLHttpRequestResponseType - 設置該值能夠改變響應類型,就是告訴服務器你期望的響應格式:

響應數據類型
"" (空字符串) 字符串(默認值)
"arraybuffer" ArrayBuffer
"blob" Blob
"document" Document
"json" JSON
"text" 字符串

xhr.spec 規范中定義的 XMLHttpRequestResponseType 類型如下:

enum XMLHttpRequestResponseType {
  "",
  "arraybuffer",
  "blob",
  "document",
  "json",
  "text"
};

responseXML: Document - 本次請求響應式一個 Document 對象,如果是以下情況則值為 null:

請求未成功

請求未發送

響應無法被解析成 XML 或 HTML

status: unsigned short - 請求的響應狀態碼,如 200 (表示一個成功的請求)。 (只讀)

statusText: DOMString - 請求的響應狀態信息,包含一個狀態碼和消息文本,如 "200 OK"。 (只讀)

timeout: unsigned long - 表示一個請求在被自動終止前所消耗的毫秒數。默認值為 0,意味著沒有超時時間。超時并不能應用在同步請求中,否則會拋出一個 InvalidAccessError 異常。當發生超時時,timeout 事件將會被觸發。

upload: XMLHttpRequestUpload - 可以在 upload 上添加一個事件監聽來跟蹤上傳過程

withCredentials: boolean - 表明在進行跨站 (cross-site) 的訪問控制 (Access-Control) 請求時,是否使用認證信息 (例如cookie或授權的header)。默認為 false。注意:這不會影響同站 same-site 請求

方法

abort() - 如果請求已經被發送,則立刻中止請求。

getAllResponseHeaders() - 返回所有響應頭信息(響應頭名和值),如果響應頭還沒有接收,則返回 null。注意:使用該方法獲取的 response headers 與在開發者工具 Network 面板中看到的響應頭不一致

getResponseHeader() - 返回指定響應頭的值,如果響應頭還沒有被接收,或該響應頭不存在,則返回 null。注意:使用該方法獲取某些響應頭時,瀏覽器會拋出異常,具體原因如下:

W3C的 xhr 標準中做了限制,規定客戶端無法獲取 response 中的 Set-CookieSet-Cookie2 這2個字段,無論是同域還是跨域請求。

W3C 的 cors 標準對于跨域請求也做了限制,規定對于跨域請求,客戶端允許獲取的response header字段只限于 simple response header (常見的 simple response header 如下)

Cache-Control

Content-Language

Content-Type

Expires

Last-Modified

Pragma

和 Access-Control-Expose-Headers。

open() - 初始化一個請求:

方法簽名:

void open(
   DOMString method,
   DOMString url,
   optional boolean async,
   optional DOMString user,
   optional DOMString password
);

參數:

method - 請求所使用的 HTTP 方法,如 GET、POST、PUT、DELETE

url - 請求的 URL 地址

async - 一個可選的布爾值參數,默認值為 true,表示執行異步操作。如果值為 false,則 send() 方法不會返回任何東西,直到接收到了服務器的返回數據

user - 用戶名,可選參數,用于授權。默認參數為空字符串

password - 密碼,可選參數,用于授權。默認參數為空字符串

備注:

如果 method 不是有效的 HTTP 方法或 url 地址不能被成功解析,將會拋出 SyntaxError 異常

如果請求方法(不區分大小寫)為 CONNECTTRACETRACK 將會拋出 SecurityError 異常

overrideMimeType() - 重寫由服務器返回的 MIME 類型。例如,可以用于強制把響應流當做 text/xml 來解析,即使服務器沒有指明數據是這個類型。注意:這個方法必須在 send() 之前被調用。

send() - 發送請求。如果該請求是異步模式(默認),該方法會立刻返回。相反,如果請求是同步模式,則直到請求的響應完全接受以后,該方法才會返回。注意:所有相關的事件綁定必須在調用 send() 方法之前進行。

方法簽名:

void send();
void send(ArrayBuffer data);
void send(Blob data);
void send(Document data);
void send(DOMString? data);
void send(FormData data);

setRequestHeader() - 設置 HTTP 請求頭信息。注意:在這之前,你必須確認已經調用了 open() 方法打開了一個 url

方法簽名:

void setRequestHeader(
   DOMString header,
   DOMString value
);

參數:

header - 請求頭名稱

value - 請求頭的值

sendAsBinary() - 發送二進制的 send() 方法的變種。

方法簽名:

void sendAsBinary(
   in DOMString body
);

參數:

body - 消息體

瀏覽器兼容性

Desktop

Feature Chrome Firefox (Gecko) Internet Explorer Opera Safari (WebKit)
Basic support (XHR1) 1 1.0 5 (via ActiveXObject)7 (XMLHttpRequest) (Yes) 1.2
send(ArrayBuffer) 9 9 ? 11.60 ?
send(Blob) 7 3.6 ? 12 ?
send(FormData) 6 4 ? 12 ?
response 10 6 10 11.60 ?
responseType = "arraybuffer" 10 6 10 11.60 ?
responseType = "blob" 19 6 10 12 ?
responseType = "document" 18 11 未實現 未實現 未實現
responseType = "json" 未實現 10 未實現 12 未實現
Progress Events 7 3.5 10 12 ?
withCredentials 3 3.5 10 12 4
事件

loadstart - 當程序開始加載時,loadstart 事件將被觸發。

progress - 進度事件會被觸發用來指示一個操作正在進行中。

abort - 當一個資源的加載已中止時,將觸發?abort 事件。

error - 當一個資源加載失敗時會觸發error事件。

load - 當一個資源及其依賴資源已完成加載時,將觸發load事件。

timeout - 當進度由于預定時間到期而終止時,會觸發timeout?事件。

loadend - 當一個資源加載進度停止時 (例如,在已經分派“錯誤”,“中止”或“加載”之后),觸發loadend事件。

readystatechange - readystatechange 事件會在 document.readyState屬性發生變化時觸發。

XMLHttpRequest Level 1 XMLHttpRequest Level 1 使用

首先,創建一個 XMLHttpRequest 對象:

var xhr = new XMLHttpRequest();

然后,向服務器發出一個 HTTP 請求:

xhr.open("GET", "example.php");
xhr.send();

接著,就等待遠程主機做出回應。這時需要監控XMLHttpRequest對象的狀態變化,指定回調函數。

xhr.onreadystatechange = function(){
  if ( xhr.readyState == 4 && xhr.status == 200 ) {
     alert( xhr.responseText );
  } else {
     alert( xhr.statusText );
  }
};

上面的代碼包含了老版本 XMLHttpRequest 對象的主要屬性:

xhr.readyState: XMLHttpRequest對象的狀態,等于4表示數據已經接收完畢。

xhr.status:服務器返回的狀態碼,等于200表示一切正常。

xhr.responseText:服務器返回的文本數據。

xhr.statusText:服務器返回的狀態文本。

XMLHttpRequest Level 1 缺點

只支持文本數據的傳送,無法用來讀取和上傳二進制文件。

傳送和接收數據時,沒有進度信息,只能提示有沒有完成。

受到"同域限制"(Same Origin Policy),只能向同一域名的服務器請求數據。

XMLHttpRequest Level 2

XMLHttpRequest Level 2 針對 XMLHttpRequest Level 1 的缺點,做了大幅改進。具體如下:

可以設置HTTP請求的超時時間。

可以使用FormData對象管理表單數據。

可以上傳文件。

可以請求不同域名下的數據(跨域請求)。

可以獲取服務器端的二進制數據。

可以獲得數據傳輸的進度信息。

設置超時時間

新版本 XMLHttpRequest 對象,增加了 timeout 屬性,可以設置HTTP請求的時限。

 xhr.timeout = 3000;

上面的語句,將最長等待時間設為3000毫秒。過了這個時限,就自動停止HTTP請求。與之配套的還有一個timeout事件,用來指定回調函數。

xhr.ontimeout = function(event){
  console.log("請求超時");
}
FormData 對象

AJAX 操作往往用來傳遞表單數據。為了方便表單處理,HTML 5新增了一個 FormData 對象,可以用于模擬表單。

FormData 簡介

構造函數 FormData()

用于創建一個新的 FormData 對象。

語法

var formData = new FormData(form)

參數

form 可選 - 一個 HTML 上的

表單元素。當使用 form 參數,創建的 FormData 對象會自動將 form 中的表單值也包含進去,文件內容會被編碼

FormData 使用

首先,新建一個 FormData 對象:

var formData = new FormData();

然后,為它添加表單項:

formData.append("username", "semlinker");
formData.append("id", 2005821040);

最后,直接傳送這個FormData對象。這與提交網頁表單的效果,完全一樣。

xhr.send(formData);

FormData 對象也可以用來獲取網頁表單的值。

var form = document.getElementById("myform"); // 獲取頁面上表單對象
var formData = new FormData(form);
formData.append("username", "semlinker"); // 添加一個表單項
xhr.open("POST", form.action);
xhr.send(formData);
上傳文件

新版 XMLHttpRequest 對象,不僅可以發送文本信息,還可以上傳文件。

1.為了上傳文件, 我們得先選中一個文件. 一個 type 為 file 的 input 輸入框

2.然后用 FormData 對象包裹選中的文件

var input = document.getElementById("input"),
    formData = new FormData();
formData.append("file",input.files[0]); // file名稱與后臺接收的名稱一致

3.設置上傳地址和請求方法

var url = "http://localhost:3000/upload",
    method = "POST";

4.發送 FormData 對象

xhr.send(formData);
跨域資源共享 (CORS)

新版本的 XMLHttpRequest 對象,可以向不同域名的服務器發出 HTTP 請求。這叫做 "跨域資源共享"(Cross-origin resource sharing,簡稱 CORS)。

使用"跨域資源共享"的前提,是瀏覽器必須支持這個功能,而且服務器端必須同意這種"跨域"。如果能夠滿足上面的條件,則代碼的寫法與不跨域的請求完全一樣。

xhr.open("GET", "http://other.server/and/path/to/script");
接收二進制數據

XMLHttpRequest Level 1 XMLHttpRequest 對象只能處理文本數據,新版則可以處理二進制數據。從服務器取回二進制數據,較新的方法是使用新增的 responseType 屬性。如果服務器返回文本數據,這個屬性的值是 "TEXT",這是默認值。較新的瀏覽器還支持其他值,也就是說,可以接收其他格式的數據。

你可以把 responseType 設為 blob,表示服務器傳回的是二進制對象。

var xhr = new XMLHttpRequest();
xhr.open("GET", "/path/to/image.png");
xhr.responseType = "blob";
xhr.send();

接收數據的時候,用瀏覽器自帶的 Blob 對象即可。

一個 ?Blob 對象表示一個不可變的, 原始數據的類似文件對象。Blob 表示的數據不一定是一個 JavaScript 原生格式。?File?接口基于Blob,繼承 blob功能并將其擴展為支持用戶系統上的文件。

var blob = new Blob([xhr.response], {type: "image/png"});

更多示例請參考?發送和接收二進制數據?。

進度信息

新版本的 XMLHttpRequest 對象,傳送數據的時候,有一個 progress 事件,用來返回進度信息。

它分成上傳和下載兩種情況。下載的 progress 事件屬于 XMLHttpRequest 對象,上傳的 progress 事件屬于XMLHttpRequest.upload 對象。

我們先定義progress事件的回調函數:

xhr.onprogress = updateProgress;
xhr.upload.onprogress = updateProgress;

然后,在回調函數里面,使用這個事件的一些屬性。

function updateProgress(event) {
  if (event.lengthComputable) {
    var percentComplete = event.loaded / event.total;
  }
}

上面的代碼中,event.total 是需要傳輸的總字節,event.loaded 是已經傳輸的字節。如果event.lengthComputable 不為真,則 event.total 等于0。

各個瀏覽器 XMLHttpRequest Level 2 的兼容性 - Can I use/xhr2

XHR 下載數據

XHR 可以傳輸基于文本和二進制數據。實際上,瀏覽器可以為各種本地數據類型提供自動編碼和解碼,這樣可以讓應用程序將這些類型直接傳遞給XHR,以便正確編碼,反之亦然,這些類型可以由瀏覽器自動解碼:

ArrayBuffer - 固定長度二進制數據緩沖區

Blob - 二進制不可變數據

Document - HTML或XML文檔

JSON - JavaScript Object Notation

Text - 普通文本

XHR 下載圖片示例:

var xhr = new XMLHttpRequest();
    xhr.open("GET", "https://avatars2.githubusercontent.com/u/4220799?v=3");
    xhr.responseType = "blob"; // 1

    xhr.onload = function() {
        if (this.status == 200) {
            var img = document.createElement("img");
            img.src = window.URL.createObjectURL(this.response); // 2
            img.onload = function() {
                window.URL.revokeObjectURL(this.src); //3
            };
            document.body.appendChild(img);
        }
    };
    xhr.send();

(1) 設置響應的數據類型為 blob

(2) 基于Blob創建一個唯一的對象URL,并作為圖片的源地址 (URL.createObjectURL())

(3) 圖片加載成功后釋放對象的URL(URL.revokeObjectURL())

XHR 上傳數據

通過 XHR 上傳數據對于所有數據類型來說都是簡單而有效的。實際上,唯一的區別是當我們在XHR請求中調用 send() 時,我們需傳遞不同的數據對象。其余的由瀏覽器處理:

var xhr = new XMLHttpRequest();
xhr.open("POST","/upload");
xhr.onload = function() { ... };
xhr.send("text string"); // 1

var formData = new FormData(); // 2
formData.append("id", 123456);
formData.append("topic", "performance");

var xhr = new XMLHttpRequest();
xhr.open("POST", "/upload");
xhr.onload = function() { ... };
xhr.send(formData); // 3

var xhr = new XMLHttpRequest();
xhr.open("POST", "/upload");
xhr.onload = function() { ... };
var uInt8Array = new Uint8Array([1, 2, 3]); // 4
xhr.send(uInt8Array.buffer); // 5

(1) 發送普通的文本到服務器

(2) 通過 FormData API 創建動態表單

(3) 發送 FormData 數據到服務器

(4) 創建 Unit8Array 數組 (Uint8Array 數組類型表示一個8位無符號整型數組,創建時內容被初始化為0)

(5) 發送二進制數據到服務器

XHR send() 方法簽名:

void send();
void send(ArrayBuffer data);
void send(Blob data);
void send(Document data);
void send(DOMString? data);
void send(FormData data);

除此之外,XHR 還支持大文件分塊傳輸:

var blob = ...; // 1

const BYTES_PER_CHUNK = 1024 * 1024; // 2
const SIZE = blob.size;

var start = 0;
var end = BYTES_PER_CHUNK;

while(start < SIZE) { // 3
  var xhr = new XMLHttpRequest();
  xhr.open("POST", "/upload");
  xhr.onload = function() { ... };

  xhr.setRequestHeader("Content-Range", start+"-"+end+"/"+SIZE); // 4
  xhr.send(blob.slice(start, end)); // 5

  start = end;
  end = start + BYTES_PER_CHUNK;
}

(1) 一個任意的數據塊 (二進制或文本)

(2) 將數據庫大小設置為 1MB

(3) 迭代提供的數據,增量為1MB

(4) 設置上傳的數據范圍 (Content-Range請求頭)

(5) 通過 XHR 上傳 1MB 數據塊

監聽上傳和下載進度

XHR 對象提供了一系列 API,用于監聽進度事件,表示請求的當前狀態:

事件類型 描述 觸發次數
loadstart 開始傳輸 1次
progress 傳輸中 0次或多次
error 傳輸中出現錯誤 0次或1次
abort 傳輸被用戶取消 0次或1次
load 傳輸成功 0次或1次
loadend 傳輸完成 1次

每個 XHR 傳輸都以 loadstart 事件開始,并以 loadend 事件結束,并在這兩個事件期間觸發一個或多個附加事件來指示傳輸的狀態。因此,為了監控進度,應用程序可以在 XHR 對象上注冊一組 JavaScript 事件偵聽器:

var xhr = new XMLHttpRequest();
xhr.open("GET","/resource");
xhr.timeout = 5000; // 1

xhr.addEventListener("load", function() { ... }); // 2
xhr.addEventListener("error", function() { ... }); // 3

var onProgressHandler = function(event) {
  if(event.lengthComputable) {
    var progress = (event.loaded / event.total) * 100; // 4
    ...
  }
}

xhr.upload.addEventListener("progress", onProgressHandler); // 5
xhr.addEventListener("progress", onProgressHandler); // 6
xhr.send();

(1) 設置請求超時時間為 5,000 ms (默認無超時時間)

(2) 注冊成功回調

(3) 注冊異常回調

(4) 計算已完成的進度

(5) 注冊上傳進度事件回調

(6) 注冊下載進度事件回調

使用XHR流式傳輸數據

在某些情況下,應用程序可能需要或希望逐步處理數據流:將數據上傳到服務器,使其在客戶機上可用,或者在從服務器下載數據時,進行流式處理。

var xhr = new XMLHttpRequest();
xhr.open("GET", "/stream");
xhr.seenBytes = 0;

xhr.onreadystatechange = function() {  // 1
  if(xhr.readyState > 2) {
    var newData = xhr.responseText.substr(xhr.seenBytes); // 2
    // process newData
    xhr.seenBytes = xhr.responseText.length; // 3
  }
};

xhr.send();

(1) 監聽 onreadystatechange 事件

(2) 從部分響應中提取新數據

(3) 更新處理的字節偏移

這個例子可以在大多數現代瀏覽器中使用。但是,性能并不好,而且還有大量的注意事項和問題:

請注意,我們正在手動跟蹤所看到字節的偏移量,然后手動分割數據:responseText 正在緩沖完整的響應!對于小的傳輸,這可能不是一個問題,但對于更大的下載,特別是在內存受限的設備,如手機,這是一個問題。釋放緩沖響應的唯一方法是完成請求并打開一個新的請求。

部分響應只能從 responseText 屬性中讀取,這將限制為僅限文本傳輸。沒有辦法讀取二進制傳輸的部分響應。

一旦讀取了部分數據,我們必須識別消息邊界:應用程序邏輯必須定義自己的數據格式,然后緩沖并解析流以提取單個消息。

瀏覽器在處理緩沖數據方面有所不同:一些瀏覽器可能會立即釋放數據,而其他瀏覽器可能會緩沖小的響應并等到積累到一定大小的數據塊才釋放它們。

瀏覽器對不同 Content-Type 資源類型的處理方式不同,對于某些資源類型允許逐步讀取 - 例如,text / html 類型,而其他 Content-Type 類型只能使用 application / x-javascript。

XHR 定時輪詢

從服務器檢索更新的最簡單的策略之一是讓客戶端進行定期檢查:客戶端可以以周期性間隔(輪詢服務器)啟動后臺XHR請求,以檢查更新。如果新數據在服務器上可用,則在響應中返回,否則響應為空。

定時輪詢的方式很簡單,但如果定時間隔很短的話,也是很低效。因此設置合適的時間間隔顯得至關重要:輪詢間隔時間過長,會導致更新不及時,然而間隔時間過短的話,則會導致客戶端與服務器不必要的流程和高開銷。接下來我們來看一個簡單的示例:

function checkUpdates(url) {
  var xhr = new XMLHttpRequest();
  xhr.open("GET", url);
  xhr.onload = function() { ... }; // 1
  xhr.send();
}

setInterval(function() { checkUpdates("/updates") }, 60000); // 2

(1) 處理服務端接收的數據

(2) 設置定時輪詢時間為 60s

定時輪詢會產生以下的問題:

每個 XHR 請求都是一個獨立的 HTTP 請求,平均來說,HTTP 的請求頭可能會引起大約 800 字節的開銷 (不帶HTTP cookie)。

每個瀏覽器發起 HTTP 請求時都將攜帶額外的 500 - 800 字節的元數據 (請求頭),如 user-agent、accept、Cache-Control 緩存控制頭等。更糟糕的是,500 - 800 字節是理想的情況,如果攜帶 Cookies 信息,那么這個數值將會更大。總而言之,這些未壓縮的 HTTP 元數據會引起很大開銷。

如果數據能夠在間隔期間順序到達,那么定時輪詢可以正常工作。但我們并沒有任何機制保證數據的正常接收。另外周期性輪詢也將會引起服務器上可用的消息及其傳送到客戶端之間引入額外的延遲。簡單的理解是如果有輪詢期間有新的可用消息,客戶端是不會馬上收到此新消息,而是要等到下一次輪詢的時候,才能獲取最新數據。

除非仔細考慮,不然輪詢通常會成為無線網絡上昂貴的性能反模式。頻繁地輪詢會大量的消耗移動設備的電量。

輪詢開銷

平均每個 HTTP 1.x 請求會增加大約 800字節的請求和響應開銷 (詳細信息可以查看 - Measuring and Controlling Protocol Overhead) 。另外在客戶端登錄后,我們還將產生一個額外的身份驗證 cookie 和 消息ID; 假設這又增加了50個字節。因此,不返回新消息的請求將產生 850字節開銷!現在假設我們有10,000個客戶端,所有的輪詢間隔時間都是60秒:
$$
(850 bytes 8 bits 10,000) / 60 seconds ≈ 1.13 Mbps
$$
每個客戶端在每個請求上發送 850 字節的數據,這轉換為每秒 167 個請求,服務器上的吞吐量大約為 1.13 Mbps!這不是一個固定的值,此外該計算值還是在假設服務器沒有向任何客戶端傳遞任何新的消息的理想情況下計算而得的。

XHR 長輪詢

周期性輪詢的挑戰在于有可能進行許多不必要的和空的檢查。考慮到這一點,如果我們對輪詢工作流程進行了輕微的修改,而不是在沒有更新可用的情況下返回一個空的響應,我們可以保持連接空閑,直到更新可用嗎?

(圖片來源 - https://hpbn.co/xmlhttprequest/)

通過保持長連接,直到更新可用,數據可以立即發送到客戶端,一旦它在服務器上可用。因此,長時間輪詢為消息延遲提供了最佳的情況,并且還消除了空檢查,這減少了 XHR 請求的數量和輪詢的總體開銷。一旦更新被傳遞,長的輪詢請求完成,并且客戶端可以發出另一個長輪詢請求并等待下一個可用的消息:

function checkUpdates(url) {
  var xhr = new XMLHttpRequest();
  xhr.open("GET", url);
  xhr.onload = function() { // 1
    ...
    checkUpdates("/updates"); // 2
  };
  xhr.send();
}

checkUpdates("/updates"); // 3

(1) 處理接收到的數據并啟動下一輪檢測更新

(2) 啟動下一輪檢測更新

(3) 發起首次更新請求

那么長時間輪詢總是比定期輪詢更好的選擇?除非消息到達率已知且不變,否則長輪詢將始終提供更短的消息延遲。

另一方面,開銷討論需要更細微的觀點。首先,請注意,每個傳遞的消息仍然引起相同的 HTTP 開銷;每個新消息都是獨立的 HTTP 請求。但是,如果消息到達率高,那么長時間輪詢會比定期輪詢發出更多的XHR請求!

長輪詢通過最小化消息延遲來動態地適應消息到達速率,這是您可能想要的或可能不需要的行為。如果對消息延遲要求不高的話,則定時輪詢可能是更有效的傳輸方式 - 例如,如果消息更新速率較高,則定時輪詢提供簡單的 "消息聚合" 機制 (即合并一定時間內的消息),這可以減少請求數量并提高移動設備的電池壽命。

XMLHttpRequest 庫 Mock.js

Mock.js 是一款模擬數據生成器,旨在幫助前端攻城師獨立于后端進行開發,幫助編寫單元測試。提供了以下模擬功能:

根據數據模板生成模擬數據

模擬 Ajax 請求,生成并返回模擬數據

基于 HTML 模板生成模擬數據

詳細信息,請查看 - Mock.js 文檔

Zone.js

Zone 是下一個 ECMAScript 規范的建議之一。Angular 團隊實現了 JavaScript 版本的 zone.js ,它是用于攔截和跟蹤異步工作的機制。

Zone 是一個全局的對象,用來配置有關如何攔截和跟蹤異步回調的規則。Zone 有以下能力:

攔截異步任務調度,如 setTimeout、setInterval、XMLHttpRequest 等

提供了將數據附加到 zones 的方法

為異常處理函數提供正確的上下文

攔截阻塞的方法,如 alert、confirm 方法

zone.js 內部使用 Monkey Patch 方式,攔截 XMLHttpRequest.prototype 對象中的 open、send、abort 等方法。

// zone.js 源碼片段
var openNative = patchMethod(window.XMLHttpRequest.prototype, "open", function () { 
    return function (self, args) {
        self[XHR_SYNC] = args[2] == false;
        return openNative.apply(self, args);
    }; 
});
Oboe.js

Oboe.js 通過將 HTTP 請求-應答模型封裝在一個漸進流式接口中,幫助網頁應用快速應答。它將 streaming 和downloading 間的轉換與SAX和DOM間JSON的解析整合在一起。它是個非常小的庫,不依賴于其他程序庫。它可以在 ajax 請求結束前就開始解析 json 變得十分容易,從而提高應用的應答速度。另外,它支持 Node.js 框架,還可以讀入除了 http 外的其他流。

有興趣的讀者,推薦看一下官網的可交互的演示示例 - Why Oboe.js

(備注:該庫就是文中 - 使用XHR流式傳輸數據章節的實際應用,不信往下看)

// oboe-browser.js 源碼片段
function handleProgress() {            
    var textSoFar = xhr.responseText,
        newText = textSoFar.substr(numberOfCharsAlreadyGivenToCallback);
    if( newText ) {
        emitStreamData( newText );
    } 
    numberOfCharsAlreadyGivenToCallback = len(textSoFar);
}
fetch.js

fetch 函數是一個基于 Promise 的機制,用于在瀏覽器中以編程方式發送 Web 請求。該項目是實現標準 Fetch 規范的一個子集的 polyfill ,足以作為傳統 Web 應用程序中 XMLHttpRequest 的代替品。

詳細信息,請參考 - Github - fetch

Fetch API 兼容性,請參考 - Can I use Fetch

XMLHttpRequest 代碼片段 ArrayBuffer 對象轉為字符串
function ab2str(buf) {
  return String.fromCharCode.apply(null, new Uint16Array(buf));
}

代碼片段來源 - ArrayBuffer與字符串的互相轉換

字符串轉 ArrayBuffer對象
function str2ab(str) {
  var buf = new ArrayBuffer(str.length * 2); // 每個字符占用2個字節
  var bufView = new Uint16Array(buf);
  for (var i = 0, strLen = str.length; i < strLen; i++) {
    bufView[i] = str.charCodeAt(i);
  }
  return buf;
}

代碼片段來源 - ArrayBuffer與字符串的互相轉換

創建 XHR 對象 兼容所有瀏覽器
// Provide the XMLHttpRequest class for IE 5.x-6.x:
// Other browsers (including IE 7.x-8.x) ignore this
//   when XMLHttpRequest is predefined
var xmlHttp;
if (typeof XMLHttpRequest != "undefined") {
    xmlHttp = new XMLHttpRequest();
} else if (window.ActiveXObject) {
    var aVersions = ["Msxml2.XMLHttp.5.0", "Msxml2.XMLHttp.4.0", 
        "Msxml2.XMLHttp.3.0", "Msxml2.XMLHttp", "Microsoft.XMLHttp"];
    for (var i = 0; i < aVersions.length; i++) {
        try {
            xmlHttp = new ActiveXObject(aVersions[i]);
            break;
        } catch (e) {}
    }
}
精簡版
var xmlHttp;
if (typeof XMLHttpRequest != "undefined") {
    xmlHttp = new XMLHttpRequest();
} else if (window.ActiveXObject) {
    try {
       xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
    } catch (e) {} 
}
sendAsBinary() polyfill
if (!XMLHttpRequest.prototype.sendAsBinary) {
  XMLHttpRequest.prototype.sendAsBinary = function (sData) {
    var nBytes = sData.length, ui8Data = new Uint8Array(nBytes);
    for (var nIdx = 0; nIdx < nBytes; nIdx++) {
      ui8Data[nIdx] = sData.charCodeAt(nIdx) & 0xff;
    }
    this.send(ui8Data);
  };
}
獲取 XMLHttpRequest 響應體
function readBody(xhr) {
    var data;
    if (!xhr.responseType || xhr.responseType === "text") {
        data = xhr.responseText;
    } else if (xhr.responseType === "document") {
        data = xhr.responseXML;
    } else {
        data = xhr.response;
    }
    return data;
}

應用示例:

var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
    if (xhr.readyState == 4) {
        console.log(readBody(xhr));
    }
}
xhr.open("GET", "https://www.baidu.com", true);
xhr.send(null);
獲取 responseURL
export function getResponseURL(xhr: any): string {
  if ("responseURL" in xhr) {
    return xhr.responseURL;
  }
  if (/^X-Request-URL:/m.test(xhr.getAllResponseHeaders())) {
    return xhr.getResponseHeader("X-Request-URL");
  }
  return;
}

代碼片段來源 - Github - @angular/http - http_utils.ts

驗證請求是否成功
export const isSuccess = (status: number): boolean => (status >= 200 && status < 300);

代碼片段來源 - Github - @angular/http - http_utils.ts

解析查詢參數為Map對象
function paramParser(rawParams: string = ""): Map {
  const map = new Map();
  if (rawParams.length > 0) {
    const params: string[] = rawParams.split("&");
    params.forEach((param: string) => {
      const eqIdx = param.indexOf("=");
      const [key, val]: string[] =
          eqIdx == -1 ? [param, ""] : [param.slice(0, eqIdx), param.slice(eqIdx + 1)];
      const list = map.get(key) || [];
      list.push(val);
      map.set(key, list);
    });
  }
  return map;
}

代碼片段來源 - Github - @angular/http - url_search_params.ts

ts 轉換為 js 的代碼如下:

   function paramParser(rawParams) {
        if (rawParams === void 0) { rawParams = ""; }
        var map = new Map();
        if (rawParams.length > 0) {
            var params = rawParams.split("&");
            params.forEach(function (param) {
                var eqIdx = param.indexOf("=");
                var _a = eqIdx == -1 ? [param, ""] : 
                    [param.slice(0, eqIdx), param.slice(eqIdx + 1)], key = _a[0], 
                        val = _a[1];
                var list = map.get(key) || [];
                list.push(val);
                map.set(key, list);
            });
        }
        return map;
    }
XHR 下載圖片
var xhr = new XMLHttpRequest();
    xhr.open("GET", "https://avatars2.githubusercontent.com/u/4220799?v=3");
    xhr.responseType = "blob";

    xhr.onload = function() {
        if (this.status == 200) {
            var img = document.createElement("img");
            img.src = window.URL.createObjectURL(this.response); 
            img.onload = function() {
                window.URL.revokeObjectURL(this.src); 
            };
            document.body.appendChild(img);
        }
    };
    xhr.send();
XHR 上傳數據 發送普通文本
var xhr = new XMLHttpRequest();
xhr.open("POST","/upload");
xhr.onload = function() { ... };
xhr.send("text string"); 
發送FormData
var formData = new FormData(); 
formData.append("id", 123456);
formData.append("topic", "performance");

var xhr = new XMLHttpRequest();
xhr.open("POST", "/upload");
xhr.onload = function() { ... };
xhr.send(formData); 
發送 Buffer
var xhr = new XMLHttpRequest();
xhr.open("POST", "/upload");
xhr.onload = function() { ... };
var uInt8Array = new Uint8Array([1, 2, 3]); 
xhr.send(uInt8Array.buffer);
XHR 上傳進度條

progress 元素

0

定義 progress 事件的回調函數

xhr.upload.onprogress = function (event) {
  if (event.lengthComputable) {
      var complete = (event.loaded / event.total * 100 | 0);
      var progress = document.getElementById("uploadprogress");
      progress.value = progress.innerHTML = complete;
  }
};

注意,progress事件不是定義在xhr,而是定義在xhr.upload,因為這里需要區分下載和上傳,下載也有一個progress事件。

我有話說 1.什么情況下 XMLHttpRequest status 會為 0?

XMLHttpRequest 返回 status 時,會執行以下步驟:

如果狀態是 UNSENT 或 OPENED,則返回 0

如果錯誤標志被設置,則返回 0

否則返回 HTTP 狀態碼

另外當訪問本地文件資源或在 Android 4.1 stock browser 中從應用緩存中獲取文件時,XMLHttpRequest 的 status 值也會為0。

示例一:

var xmlhttp;
xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET","http://www.w3schools.com/XML/cd_catalog.xml", true);
xmlhttp.onreadystatechange=function() {
  if(xmlhttp.readyState == 4) console.log("status " + xmlhttp.status);
};
xmlhttp.addEventListener("error", function (error) {
   console.dir(error);
});
xmlhttp.send();

以上代碼運行后,將會在控制臺輸出:

status 0
ProgressEvent # error 對象
2.為什么 GET 或 HEAD 請求,不能通過 send() 方法發送請求體?

client . send([body = null])

Initiates the request. The optional argument provides the request body. The argument is ignored if request method is GET or HEAD. —— xhr.spec

通過 XMLHttpRequest 規范,我們知道當請求方法是 GET 或 HEAD 時,send() 方法的 body 參數值將會被忽略。那么對于我們常用的 GET 請求,我們要怎么傳遞參數呢?解決參數傳遞可以使用以下兩種方式:

URL 傳參 - 常用方式,有大小限制大約為 2KB

請求頭傳參 - 一般用于傳遞 token 等認證信息

URL 傳參

var url = "bla.php";
var params = "somevariable=somevalue&anothervariable=anothervalue";
var http = new XMLHttpRequest();

http.open("GET", url+"?"+params, true);
http.onreadystatechange = function()
{
    if(http.readyState == 4 && http.status == 200) {
        alert(http.responseText);
    }
}
http.send(null); // 請求方法是GET或HEAD時,設置請求體為空

在日常開發中,我們最常用的方式是傳遞參數對象,因此我們可以封裝一個 formatParams() 來實現參數格式,具體示例如下:

formatParams() 函數:

function formatParams( params ){
  return "?" + Object
        .keys(params)
        .map(function(key){
          return key+"="+params[key]
        })
        .join("&")
}

應用示例:

var endpoint = "https://api.example.com/endpoint";
var params = {
  a: 1, 
  b: 2,
  c: 3
};
var url = endpoint + formatParams(params); // 實際應用中需要判斷endpoint是否已經包含查詢參數
// => "https://api.example.com/endpoint?a=1&b=2&c=3";

一些常用的 AJAX 庫,如 jQuery、zepto 等,內部已經封裝了參數序列化的方法 (如:jquery.param),我們直接調用頂層的 API 方法即可。

(備注:以上示例來源 - stackoverflow - How do I pass along variables with XMLHttpRequest)

請求頭傳參 - (身份認證)

var xhr = new XMLHttpRequest();
xhr.open("POST", "/server", true);

xhr.setRequestHeader("x-access-token", "87a476494db6ec53d0a206589611aa3f");
xhr.onreadystatechange = function() {
    if(xhr.readyState == 4 && xhr.status == 200) {
       // handle data 
    }
};
xhr.send("foo=bar&lorem=ipsum"); 

詳細的身份認證信息,請參考 - JSON Web Tokens

3.XMLHttpRequest 請求體支持哪些格式?

send() 方法簽名:

void send();

void send(ArrayBuffer data);

void send(Blob data);

void send(Document data);

void send(DOMString? data);

void send(FormData data);

POST請求示例

發送 POST 請求通常需要以下步驟:

使用 open() 方法打開連接時,設定 POST 請求方法和請求 URL地址

設置正確的 Content-Type 請求頭

設置相關的事件監聽

設置請求體,并使用 send() 方法,發送請求

var xhr = new XMLHttpRequest();
xhr.open("POST", "/server", true);

//Send the proper header information along with the request
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

xhr.onreadystatechange = function() {
    if(xhr.readyState == 4 && xhr.status == 200) {
        // handle data
    }
}
xhr.send("foo=bar&lorem=ipsum"); 
// xhr.send("string"); 
// xhr.send(new Blob()); 
// xhr.send(new Int8Array()); 
// xhr.send({ form: "data" }); 
// xhr.send(document);
4.什么是簡單請求和預請求 (preflight request) ?

簡單請求

一些不會觸發 CORS preflight 的請求被稱為 "簡單請求",雖然 Fetch (定義 CORS的) 不使用這個術語。滿足下述條件的就是 "簡單請求":

只允許下列方法:

GET

HEAD

POST

除了用戶代理自動設置的頭部外(比如 Connection, User-Agent ,或者其他任意的 Fetch 規范定義的 禁止的頭部名 ),唯一允許人工設置的頭部是 Fetch 規范定義的 CORS-safelisted request-header,如下:

Accept

Accept-Language

Content-Language

Content-Type

允許的 Content-Type 值有:

application/x-www-form-urlencoded

multipart/form-data

text/plain

預請求

不同于上面討論的簡單請求,"預請求" 要求必須先發送一個 OPTIONS 方法請求給目的站點,來查明這個跨站請求對于目的站點是不是安全的可接受的。這樣做,是因為跨站請求可能會對目的站點的數據產生影響。 當請求具備以下條件,就會被當成預請求處理:

使用下述方法以外的請求:

GET

HEAD

POST

除了用戶代理自動設置的頭部外(比如 Connection, User-Agent ,或者其他任意的 Fetch 規范定義的 “禁止的頭部名” ),預請求不包括 Fetch 規范定義的 "CORS-safelisted request-header":

Accept

Accept-Language

Content-Language

Content-Type

Content-Type 頭部的值除了下列之外的:

application/x-www-form-urlencoded

multipart/form-data

text/plain

詳細的信息,請參考 - MDN - HTTP 訪問控制 (CORS)

5.XMLHttpRequest 對象垃圾回收機制是什么?

在以下情況下,XMLHttpRequest 對象不會被垃圾回收:

如果 XMLHttpRequest 對象的狀態是 OPENED 且已設置 send() 的標識符

XMLHttpRequest 對象的狀態是 HEADERS_RECEIVED (已獲取響應頭)

XMLHttpRequest 對象的狀態是 LOADING (正在下載響應體),并且監聽了以下一個或多個事件:readystatechange、progress、abort、error、load、timeout、loadend

如果 XMLHttpRequest 對象在連接尚存打開時被垃圾回收機制回收了,用戶代理必須終止請求。

6.GET 和 POST 請求的區別?

對于 GET 請求,瀏覽器會把 HTTP headers 和 data 一并發送出去,服務器響應 200。

而對于 POST 請求,瀏覽器會先發送 HTTP headers,服務器響應 100 continue ,瀏覽器再發送 data,服務器響應 200。

詳細的信息,請參考 - 99%的人都理解錯了HTTP中GET與POST的區別

7.怎樣防止重復發送 AJAX 請求?

setTimeout + clearTimeout - 連續的點擊會把上一次點擊清除掉,也就是ajax請求會在最后一次點擊后發出去

disable 按鈕

緩存已成功的請求,若請求參數一致,則直接返回,不發送請求

詳細的信息,請參考 - 知乎 - 怎樣防止重復發送 Ajax 請求

8、AJAX 站點怎么做 SEO 優化

眾所周知,大部分的搜索引擎爬蟲都不會執行 JS,也就是說,如果頁面內容由 Ajax 返回的話,搜索引擎是爬取不到部分內容的,也就無從做 SEO (搜索引擎優化)了。國外的 prerender.io 網站提供了一套比較成熟的方案,但是需要付費的。接下來我們來看一下,怎么 PhantomJS 為我們的站點做 SEO。

詳細的信息,請參考 - 用PhantomJS來給AJAX站點做SEO優化

精品文章

XMLHttpRequest 2新技巧

阮一峰 - XMLHttpRequest Level 2 使用指南

segmentfault - 你真的會使用XMLHttpRequest嗎?

Github - Ajax 知識體系大梳理

參考資源

XMLHttpRequest 標準

High Performance Browser Networking - XMLHttpRequest

msdn - ActiveXObject 對象.aspx)

mdn - XMLHttpRequest

XMLHttpRequest 2新技巧

阮一峰 - XMLHttpRequest Level 2 使用指南

segmentfault - 你真的會使用XMLHttpRequest嗎?

Github - Ajax 知識體系大梳理

JavaScript 標準參考教程 (alpha) - 二進制數組?

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/82364.html

相關文章

  • 你不知道CORS跨域資源共享

    摘要:同源策略禁止使用對象向不同源的服務器地址發起請求。借助于決解同源策略決解同源策略,新方案跨域資源共享這里講的重點跨域資源共享提供的標準跨域解決方案,是一個由瀏覽器共同遵循的一套控制策略,通過的來進行交互主要通過后端來設置配置項。 了解下同源策略 源(origin)*:就是協議、域名和端口號; 同源: 就是源相同,即協議、域名和端口完全相同; 同源策略:同源策略是瀏覽器的一個安全...

    Gu_Yan 評論0 收藏0
  • 【筆記】 你不知道JS讀書筆記——異步

    摘要:異步請求線程在在連接后是通過瀏覽器新開一個線程請求將檢測到狀態變更時,如果設置有回調函數,異步線程就產生狀態變更事件,將這個回調再放入事件循環隊列中。 基礎:瀏覽器 -- 多進程,每個tab頁獨立一個瀏覽器渲染進程(瀏覽器內核) 每個瀏覽器渲染進程是多線程的,主要包括:GUI渲染線程 JS引擎線程 也稱為JS內核,負責處理Javascript腳本程序。(例如V8引擎) JS引擎線程負...

    junnplus 評論0 收藏0
  • JavaScript中發出HTTP請求最常用方法

    摘要:在本文中,我們將介紹一些在中發出請求的流行方法。是發出異步請求的傳統方式。如果等于,則表示請求已完成。是進行調用的最簡單方法之一。它需要三個參數請求的地址您要發送的數據和回調函數。事實上,這是制作請求的最佳和最喜歡的方式之一。 showImg(https://segmentfault.com/img/bVbdEhE?w=749&h=450);JavaScript具有很好的模塊和方法來發...

    kyanag 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<