小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

快速了解JavaScript的Ajax

 風(fēng)聲之家 2020-12-11

原創(chuàng) hireny 海人的博客 前天


概述

Ajax(Asynchronous JavaScript and XML,即異步 JavaScript 和 XML)技術(shù)用于與服務(wù)器交換數(shù)據(jù)并刷新部分頁(yè)面,實(shí)現(xiàn)更好的用戶體驗(yàn)。

Ajax 的核心對(duì)象是 XMLHttpRequest,通過(guò) XMLHttpRequest 可以在不刷新頁(yè)面的情況下請(qǐng)求特定 URL,獲取數(shù)據(jù)。由微軟實(shí)現(xiàn)并在 IE5 中支持,用于執(zhí)行異步網(wǎng)絡(luò)請(qǐng)求。雖然 Ajax 是 Asynchronous JavaScript+XML的縮寫,但Ajax通信與數(shù)據(jù)格式無(wú)關(guān),并不一定是XML格式。甚至支持 HTTP 以外的協(xié)議(如 file:// 和 FTP),盡管可能受到更多出于安全等原因的限制。

使用 Ajax 需要幾個(gè)步驟:

  1. 創(chuàng)建 XMLHttpRequest 對(duì)象。
  2. 發(fā)出 HTTP 請(qǐng)求。
  3. 接收服務(wù)器傳回的數(shù)據(jù)。
  4. 更新網(wǎng)頁(yè)數(shù)據(jù)。

總之,Ajax 就是通過(guò) XMLHttpRequest 對(duì)象發(fā)出 HTTP 請(qǐng)求,得到服務(wù)器響應(yīng)并處理。

創(chuàng)建 XMLHttpRequest

在所有現(xiàn)代瀏覽器都可以通過(guò) XMLHttpRequest 構(gòu)造函數(shù)創(chuàng)建 XMLHttpRequest 對(duì)象:

let xhr = new XMLHttpRequest();

而在老版本 IE5 和 IE6 中使用 ActiveX 對(duì)象創(chuàng)建:

let xhr = new ActiveXObject("Microsoft.XMLHTTP");

使用 XMLHttpRequest

創(chuàng)建對(duì)象后,需要使用 XMLHttpRequest 對(duì)象調(diào)用 open(type, url, async) 方法并設(shè)置三個(gè)參數(shù):

  • type:表示請(qǐng)求類型,如 "get" 、"post" 等。
  • url:表示請(qǐng)求的url。
  • async:表示請(qǐng)求是否異步。如 true表示異步請(qǐng)求,false表示同步請(qǐng)求,它會(huì)使JavaScript代碼等待服務(wù)器響應(yīng)之后在繼續(xù)執(zhí)行。

GET

最常用的 GET 請(qǐng)求方法,用于查詢服務(wù)器信息。對(duì)于 XMLHttpRequest 對(duì)象而言,GET 請(qǐng)求的參數(shù)必須正確編碼并添加到 URL 后面,然后再給 open() 方法。而最常見的錯(cuò)誤是格式不對(duì)。因此使用 encodeURIComponent() 對(duì)每個(gè)名/值進(jìn)行編碼,并且名/值對(duì)必須使用&分隔。如下所示:

xhr.open("get""example.jsp?name1=value1&name2=value2"true);

可以使用以下函數(shù)將查詢字符串參數(shù)添加到現(xiàn)有的 URL 末尾:

function addURLParam(url, name, value{
    url += (url.indexOf("?") == -1 ? "?" : "&");
    url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
    return url;
}

可以使用這個(gè)函數(shù)構(gòu)建請(qǐng)求 URL,如下面的例子所示:

let url = "example.jsp";
// 添加參數(shù)
url = addURLParam(url, "name""Nicholas");
url = addURLParam(url, "book""Professional JavaScript");
// 初始化請(qǐng)求
xhr.open("get", url, false);

這里使用 addURLParam() 函數(shù)可以保證通過(guò) XMLHttpRequest 發(fā)送請(qǐng)求的 URL 格式正確。

這里的 example.jsp 是相對(duì)位置,也可以使用絕對(duì) url。并且 open() 只是為發(fā)送請(qǐng)求做準(zhǔn)備,而不發(fā)送請(qǐng)求。

定義好發(fā)送請(qǐng)求后,就可以調(diào)用 send(data) 方法,將請(qǐng)求發(fā)送到服務(wù)器。而 send(data)方法要設(shè)置一個(gè)參數(shù),是作為請(qǐng)求體發(fā)送的數(shù)據(jù)。不需要發(fā)送的話,傳入null

xhr.send(null);

POST

而另一個(gè)請(qǐng)求方法就是 POST 請(qǐng)求,用于向服務(wù)器發(fā)送數(shù)據(jù)。每個(gè) POST 請(qǐng)求都應(yīng)在請(qǐng)求體中攜帶提交的數(shù)據(jù)。POST 請(qǐng)求體中可以包含非常多且是任意格式的數(shù)據(jù)。如下例子:

xhr.open("post""example.jsp"true);

在傳參上,POST 請(qǐng)求不用將參數(shù)添加在 URL 后面,而是使用 send() 方法將要發(fā)送的數(shù)據(jù)傳入。

默認(rèn)情況下,對(duì)服務(wù)器而言,POST 請(qǐng)求與HTML表單提交是不一樣的。服務(wù)器邏輯需要讀取原始 POST 數(shù)據(jù)才能取得瀏覽器發(fā)送的數(shù)據(jù)。不過(guò),還可以使用 XML 模擬表單提交。為此,第一步需要把 Content-Type 頭部設(shè)置為 "application/x-www-formurlencoded",這是提交表單時(shí)使用的內(nèi)容類型。第二步是創(chuàng)建對(duì)應(yīng)格式的字符串。POST 數(shù)據(jù)此時(shí)使用與查詢字符串相同的格式。如果網(wǎng)頁(yè)中確實(shí)有一個(gè)表單需要序列化并通過(guò) XMLHttpRequest 發(fā)送到服務(wù)器,則可以使用 serialize() 函數(shù)來(lái)創(chuàng)建相應(yīng)的字符串,如下所示:

function submitData({
    let xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function({
        if (xhr.readyState == 4) {
            if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
                alert(xhr.responseText);
            } else {
                alert("Request was unsuccessful: " + xhr.status);
            }
        }
    };
    xhr.open("post""postexample.jsp"true);
    xhr.setRequestHeader("Content-Type""application/x-www-form-urlencoded");
    // ID為 user-info 的表單元素
    let form = document.getElementById("user-info");
    xhr.send(serialize(form));
}

注意:POST 請(qǐng)求相比 GET 請(qǐng)求要占用更多資源。從性能方面說(shuō),發(fā)送相同數(shù)據(jù)的數(shù)據(jù),GET請(qǐng)求比 POST 請(qǐng)求快兩倍。

響應(yīng)

當(dāng)服務(wù)器收到請(qǐng)求并響應(yīng)后,XMLHttpRequest 對(duì)象會(huì)有以下屬性被填充數(shù)據(jù):

  • responseText:作為響應(yīng)體返回的文本。
  • responseXML:如果響應(yīng)的內(nèi)容類型是 "text/xml""application/xml",那就是包含響應(yīng)數(shù)據(jù)的 XML DOM 文檔。
  • status:響應(yīng)的 HTTP 狀態(tài)碼。
  • stautsText:響應(yīng)的 HTTP 狀態(tài)描述。

一般都是通過(guò) status 屬性來(lái)確保響應(yīng)是否成功返回。當(dāng) status 為 2xx 表示成功,為 304 表示資源未被修改,而是從緩存中取出的。這時(shí)的 responseText 或 responseXML 屬性中會(huì)有內(nèi)容。因此,我們可以使用 status 屬性來(lái)判斷響應(yīng)是否有效,如下所示:

xhr.open("get""example.txt"false);
xhr.send(null);

if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
    console.log(xhr.responseText);
else {
    console.log("Request was unsuccessful: " + xhr.status);
}

屬性和方法

readyState

XMLHttpRequest.readyState 屬性返回一個(gè)無(wú)符號(hào)短整型數(shù)字,表示XMLHttpRequest對(duì)象的當(dāng)前狀態(tài)。該對(duì)象會(huì)返回以下某個(gè)值:

  • 返回 0,未初始化(Uninitialized),狀態(tài)為 UNSENT。表示代理被創(chuàng)建,但尚未調(diào)用open() 方法。
  • 返回 1,狀態(tài)為 Open 已打開(Open),狀態(tài)為OPENED。表示 open() 方法已被調(diào)用,但尚未調(diào)用 send() 方法。
  • 返回 2,已發(fā)送(Sent),狀態(tài)為HEADERS_RECEIVED。表示已調(diào)用 send() 方法,并且頭部和狀態(tài)已經(jīng)可獲得,但尚未收到響應(yīng)。
  • 返回 3:接收中(Receiving),狀態(tài)為LOADING。表示已經(jīng)收到部分響應(yīng)。
  • 返回 4:已完成(Complete),狀態(tài)為DONE。表示請(qǐng)求操作已完成。意味著數(shù)據(jù)傳輸已經(jīng)徹底完成或失敗。

通信過(guò)程中,每當(dāng) XMLHttpRequest 對(duì)象狀態(tài)發(fā)送變化,readyState 屬性值就會(huì)被改變,并會(huì)觸發(fā) onreadystatechange事件。并且XMLHttpRequest對(duì)象調(diào)用abort()方法,終止請(qǐng)求,也會(huì)造成 readyState屬性變化。為保證兼容性,onreadystatechange事件應(yīng)在open()方法之前賦值。如下所示:

let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function({
    if (xhr.readyState == 4) {
        if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
            console.log(xhr.responseText);
        } else {
            alert("Request was unsuccessful: " + xhr.status);
        }
    }
};
xhr.open("get""example.txt"true);
xhr.send(null);

如果之前使用的是異步請(qǐng)求并想在響應(yīng)之前取消,可以調(diào)用 abort() 方法:

let xhr = new XMLHttpRequest();
xhr.open("get""example.jsp"true);
setTimeout(function({
    if (xhr) {
        xhr.abort();
        xhr = null;
    }
}, 5000); // 5秒后,終止 Ajax 請(qǐng)求

調(diào)用這個(gè)方法后,XMLHttpRequest 對(duì)象會(huì)停止觸發(fā)事件,并阻止訪問(wèn)這個(gè)對(duì)象上任何與響應(yīng)相關(guān)的屬性,而 readyState 屬性變?yōu)?nbsp;4status 屬性變?yōu)?nbsp;0 。中斷請(qǐng)求后,應(yīng)該取消對(duì) XMLHttpRequest  對(duì)象的引用。由于內(nèi)存問(wèn)題,不推薦重用 XMLHttpRequest 對(duì)象。

responseType

XMLHttpRequest.responseType 屬性是一個(gè)字符串,返回響應(yīng)數(shù)據(jù)的類型。允許手動(dòng)設(shè)置返回?cái)?shù)據(jù)的類型。如果設(shè)置為空字符串,則使用默認(rèn)的"text"類型。

當(dāng) responseType 設(shè)置為一個(gè)特定的類型時(shí),需確保服務(wù)器返回的類型和你所設(shè)置的類型是兼容的。如果不兼容,即使服務(wù)器返回了數(shù)據(jù),數(shù)據(jù)也會(huì)變成nullresponseType 屬性支持以下幾種值:

  1. "":當(dāng)responseType為空字符串時(shí),與 text 相同,表示服務(wù)器返回文本數(shù)據(jù)。
  2. "arraybuffer":表示服務(wù)器返回的是一個(gè)包含二進(jìn)制數(shù)據(jù)的ArrayBuffer 對(duì)象。
  3. “blob”:表示服務(wù)器返回的是一個(gè)包含二進(jìn)制數(shù)據(jù)的 Blob對(duì)象。
  4. “document”:表示服務(wù)器返回的是一個(gè)HTML Document 或 XML Document,這取決于接收數(shù)據(jù)的 MIME 類型。
  5. “json”:表示將接收到的服務(wù)器數(shù)據(jù)視為JSON來(lái)進(jìn)行解析并得到。
  6. “text”:表示服務(wù)器返回的是以DOMString對(duì)象表示的文本。

上面幾種類型之中,text類型適合大多數(shù)情況,而且直接處理文本也比較方便。document類型適合返回HTML/XML文檔的情況,這意味著,對(duì)于那些打開 CORS 的網(wǎng)站,可以直接用 Ajax 抓取網(wǎng)頁(yè),然后不用解析 HTML 字符串,直接對(duì)抓取回來(lái)的數(shù)據(jù)進(jìn)行 DOM 操作。blob 類型適合讀取二進(jìn)制數(shù)據(jù),比如圖片文件。XMLHttpRequest.responseType屬性要在調(diào)用 open() 方法之后,并且在調(diào)用 send() 方法之前調(diào)用。

let xhr = new XMLHttpRequest();
xhr.open("GET""example.jsp"true);
xhr.responseType = "json";
xhr.send(null);

response

XMLHttpRequest.response 屬性返回響應(yīng)的數(shù)據(jù)體(即 HTTP 響應(yīng)的 body 部分)。返回的類型為 ArrayBuffer、BlobDocument、ObjectDOMString中的一個(gè)。具體類型由 XMLHttpRequest.responseType 類型決定。

當(dāng)請(qǐng)求尚未完成或尚未成功,該值為 null。但當(dāng) responseType 屬性設(shè)置成 "text" 或空字符串("") 且當(dāng)請(qǐng)求狀態(tài)在LOADING時(shí),response屬性包含到目前為止該請(qǐng)求已經(jīng)取得的內(nèi)容。

let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function({
    if (xhr.readyState == 4) {
        console.log(xhr.response);
    }
}

HTTP頭部

在 HTTP 的每次請(qǐng)求和響應(yīng)中都會(huì)攜帶一些頭部字段,默認(rèn)請(qǐng)求下,XMLHttpRequest 請(qǐng)求會(huì)發(fā)送以下頭部字段。

  • Accept:瀏覽器可以處理的內(nèi)容類型。
  • Accept-Charset:瀏覽器可以顯示的字符集。
  • Accept-Encoding:瀏覽器可以處理的壓縮編碼類型。
  • Accept-Language:瀏覽器使用的語(yǔ)言。
  • Connection:瀏覽器與服務(wù)器的連接類型。
  • Cookie:頁(yè)面中設(shè)置的 Cookie
  • Host:發(fā)送請(qǐng)求的頁(yè)面所在的域。
  • Referer:發(fā)送請(qǐng)求的頁(yè)面的 URI
  • User-Agent:瀏覽器的用戶代理字符串。

XMLHttpRequest對(duì)象通過(guò)一些方法暴露與請(qǐng)求和響應(yīng)相關(guān)的頭部字段。

然而 XMLHttpRequest 對(duì)象可以使用 setRequestHeader() 方法發(fā)送 HTTP 頭部字段,接收兩個(gè)參數(shù):第一個(gè)參數(shù)是頭部字段名,第二個(gè)參數(shù)是頭部字段值。為保證請(qǐng)求頭被發(fā)送,必須在 open() 之后,send() 之前調(diào)用。如果多次調(diào)用,設(shè)同一個(gè)字段的值會(huì)合并成單一的值發(fā)送。如下所示:

let xhr = new XMLHttpRequest();
xhr.open("get""example.jsp"true);
xhr.setRequestHeader("Content-Type""application/json");
xhr.setRequestHeader("Custom-Header""Custom-Value");
xhr.send(null);

自定義頭部要區(qū)別于瀏覽器正常發(fā)送的頭部,否則會(huì)影響服務(wù)器正常響應(yīng)。默認(rèn)頭部在有些瀏覽器上可以重寫。

getResponseHeader() 方法可以返回 HTTP 頭部信息中指定的字段值,接收的參數(shù)為頭部名稱。也可以使用 getAllResponseHeaders() 方法獲取所有,返回的可能是如下所示的字符串:

Date: Sun, 14 Nov 2004 18:04:03 GMT
Server: Apache/1.3.29 (Unix)
Vary: Accept
Connection: close
Content-Type: text/html; charset=iso-8859-1

通過(guò)解析以上頭部字段的輸出,就可以知道服務(wù)器發(fā)送的所有頭部,而不需要單獨(dú)去檢查了。

XMLHttpRequest Level 2

XMLHttpRequest Level 2 是在 XMLHttpRequest Level 1 的基礎(chǔ)上進(jìn)一步的擴(kuò)展。但并非所有瀏覽器都實(shí)現(xiàn)了 XMLHttpRequest Level 2 的所有功能,也可能只實(shí)現(xiàn)了部分功能。

FormData

在 XMLHttpRequest Level 2 中新增了 FormData 類型,主要用于將數(shù)據(jù)編譯成鍵值對(duì),使用XMLHttpRequest來(lái)發(fā)送數(shù)據(jù)。也用于創(chuàng)建與表單類似格式的數(shù)據(jù)。創(chuàng)建一個(gè)FormData對(duì)象,如下所示:

let data = new FormData();
data.append("username""Clark");
data.append("account""addie");


let request = new XMLHttpRequest():
request.open("post""http:///submitform.jsp");
request.send(data);

append() 方法接收兩個(gè)參數(shù):鍵,相當(dāng)于表單字段名;值,相當(dāng)于表單字段名的值。當(dāng)然,也可以直接給 FormData 構(gòu)造函數(shù)傳入表單元素,也可以將表單中的數(shù)據(jù)作為鍵值對(duì)填充進(jìn)去,也可以附加額外的數(shù)據(jù)到FormData對(duì)象中:

let form = document.querySelector("form");
let data = new FormData(form);

data.append("serialnumber"134);

而使用 FormData之后,可以不再需要給 XMLHttpRequest對(duì)象顯式地設(shè)置任何請(qǐng)求頭部。XMLHttpRequest對(duì)象能夠識(shí)別作為 FormData對(duì)象傳入的數(shù)據(jù)類型并自動(dòng)配置相應(yīng)的頭部。

timeout

XMLHttpRequest.timeout 屬性是一個(gè)無(wú)符號(hào)長(zhǎng)整型數(shù),表示發(fā)送數(shù)據(jù)后等待的毫秒數(shù),響應(yīng)不成功則中斷請(qǐng)求。是 IE8 給 XMLHttpRequest 對(duì)象添加的屬性,并在 XMLHttpRequest Level 2 中添加了該特性。默認(rèn)值為 0,當(dāng)超時(shí)時(shí),就會(huì)觸發(fā) timeout 事件。如下所示:

let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function({
    if (xhr.readyState == 4) {
        try {
            if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
                alert(xhr.responseText);
            } else {
                alert("Request was unsuccessful: " + xhr.status);
            }
        } catch (ex) {
            // 假設(shè)由ontimeout 處理
        }
    }
};
xhr.open("get""timeout.jsp"true);
xhr.timeout = 1000// 設(shè)置1 秒超時(shí)
xhr.ontimeout = function({
    alert("Request did not return in a second.");
};
xhr.send(null);

這個(gè)例子演示了使用 timeout 設(shè)置超時(shí)。給 timeout 設(shè)置 1000 毫秒意味著,如果請(qǐng)求沒有在 1 秒鐘內(nèi)返回則會(huì)中斷。此時(shí)則會(huì)觸發(fā) ontimeout 事件處理程序,readyState 仍然會(huì)變成 4,因此也會(huì)調(diào)用 onreadystatechange 事件處理程序。不過(guò),如果在超時(shí)之后訪問(wèn)status 屬性則會(huì)發(fā)生錯(cuò)誤。為做好防護(hù),可以把檢查 status 屬性的代碼封裝在 try/catch 語(yǔ)句中。

overrideMimeType()

XMLHttpRequest.overrideMimeType() 方法用來(lái)重寫 XMLHttpRequest 響應(yīng)的 MIME 類型。是 Firefox 首次引入,在 XMLHttpRequest Level 2 中添加了該方法。因?yàn)轫憫?yīng)返回的MIME 類型決定了 XMLHttpRequest 對(duì)象如何處理響應(yīng)。例如服務(wù)器實(shí)際發(fā)送的是 XML數(shù)據(jù),但響應(yīng)頭中MIME類型設(shè)置的是text/plain,瀏覽器不會(huì)自動(dòng)解析,responseXML屬性值是null。此時(shí)調(diào)用overrideMimeType() 可以保證將響應(yīng)當(dāng)成 XML 而不是純文本來(lái)處理:

let xhr = new XMLHttpRequest();
xhr.open("get""example.jsp"true);
xhr.overrideMimeType("text/xml");
xhr.send(null);

注意:為正確覆蓋響應(yīng)的 MIME 類型,該方法必須在 send() 方法之前調(diào)用。

小結(jié)

Ajax 是無(wú)需刷新當(dāng)前頁(yè)面即可從服務(wù)器獲取數(shù)據(jù)的一種方法,其中核心對(duì)象是 XMLHttpRequest,最早由微軟發(fā)明,并在 IE5 中引入。之后,其它瀏覽器都實(shí)現(xiàn)了該對(duì)象。W3C 雖然也引入了 Web 標(biāo)準(zhǔn)。雖然不同瀏覽器有些差異,但基本使用時(shí)相對(duì)較規(guī)范的,因此可以放心使用。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多