Ajax和Comet技術(shù)總結(jié)
Ajax是一種技術(shù),一種能夠向服務(wù)器請(qǐng)求額外的數(shù)據(jù)而無(wú)需卸載頁(yè)面的技術(shù),能夠使網(wǎng)頁(yè)具備更優(yōu)的用戶體驗(yàn)。Ajax技術(shù)的核心是XMLHttpRequest對(duì)象(XHR)。本文從XHR開(kāi)始談起,理解Ajax技術(shù)的特點(diǎn),再對(duì)跨域以及Comet等技術(shù)進(jìn)行簡(jiǎn)要理解和總結(jié)。
XMLHttpRequest基本用法
XHR對(duì)象有兩個(gè)常用的方法open和send。open方法用戶啟動(dòng)一個(gè)HTTP請(qǐng)求,不過(guò)它不會(huì)真的發(fā)送HTTP請(qǐng)求。open方法接收3個(gè)參數(shù),分別表示請(qǐng)求的HTTP方法、請(qǐng)求的URL、是否異步。XHR對(duì)象的第二個(gè)方法send用于發(fā)送open所啟動(dòng)的請(qǐng)求。send方法接收1個(gè)參數(shù),表示HTTP請(qǐng)求的主體數(shù)據(jù)。如果發(fā)送的是GET請(qǐng)求這種沒(méi)有附帶主體數(shù)據(jù)的HTTP請(qǐng)求,則傳入null即可。如果是POST請(qǐng)求,則傳入需要POST的數(shù)據(jù)。下面是一個(gè)簡(jiǎn)單示例,向/api/data發(fā)起一個(gè)GET請(qǐng)求,并且是采取異步的方式發(fā)送請(qǐng)求,即該請(qǐng)求不會(huì)阻塞頁(yè)面中其他js代碼的執(zhí)行。
var xhr = new XMLHttpRequest() xhr.open("get", "/api/data", true) xhr.send(null)
請(qǐng)求得到的響應(yīng)數(shù)據(jù)會(huì)自動(dòng)填充到XHR對(duì)象的屬性上,主要有下面4個(gè)屬性:
* responseText: 響應(yīng)主體文本
* responseXML: 如果響應(yīng)內(nèi)容類型是"text/xml"或"application/xml", 這個(gè)屬性中將包含響應(yīng)數(shù)據(jù)的XML DOM文檔
* status: 響應(yīng)的HTTP狀態(tài)碼,一般可以將HTTP狀態(tài)嗎200視為成功的標(biāo)識(shí)
* statusText: HTTP狀態(tài)的說(shuō)明
XHR對(duì)象有1個(gè)readyState屬性記錄了該對(duì)象從創(chuàng)建到收到響應(yīng)數(shù)據(jù)可能會(huì)經(jīng)歷的5種狀態(tài),readyState的可能取值如下:
0: 還沒(méi)有調(diào)用open()方法初始化請(qǐng)求
1: 已經(jīng)調(diào)用open()方法但是還沒(méi)有調(diào)用send()方法
2: 已經(jīng)調(diào)用send()方法但是還沒(méi)有收到響應(yīng)
3: 收到部分響應(yīng)數(shù)據(jù),還有部分?jǐn)?shù)據(jù)沒(méi)收到
4: 收到全部響應(yīng)數(shù)據(jù),即響應(yīng)結(jié)束,數(shù)據(jù)完備
當(dāng)readyState從一個(gè)值變到另一個(gè)值的時(shí)候會(huì)觸發(fā)readystatechange事件,當(dāng)這個(gè)事件觸發(fā)的時(shí)候只需要在事件處理器里面檢查一下readyState的值是否為4,當(dāng)其值為4的時(shí)候就可以對(duì)響應(yīng)的數(shù)據(jù)做后續(xù)處理了。給readystatechange事件指定處理器必須在調(diào)用open()方法之前完成才能確??鐬g覽器兼容性。下面是簡(jiǎn)單示例。
var xhr = new XMLHttpRequest() xhr.onreadystatechange = function() { if (xhr.readyState === 4) { console.log(xhr.status, xhr.responseText) } } xhr.open("get", "/api/data", true) xhr.send(null)
XHR對(duì)象提供setRequestHeader()方法可以設(shè)置請(qǐng)求的自定義HTTP頭部信息,該方法接收兩個(gè)參數(shù),要設(shè)置的字段和該字段的值。在調(diào)用open()啟動(dòng)一個(gè)請(qǐng)求之后并且在send()發(fā)送請(qǐng)求之前調(diào)用setRequestHeader()才能設(shè)置成功。請(qǐng)求得到響應(yīng)之后,可以通過(guò)getResponseHeader()方法獲取響應(yīng)的HTTP頭部信息,該方法接收1個(gè)參數(shù),即要獲取的字段名。而通過(guò)getAllResponseHeaders()則可以獲得所有頭部信息組成的長(zhǎng)字符串。下面是簡(jiǎn)單示例。
var xhr = new XMLHttpRequest() xhr.onreadystatechange = function() { if (xhr.readyState === 4) { console.log(xhr.status, xhr.responseText) console.log(xhr.getResponseHeader('SomeKey')) console.log(xhr.getAllResponseHeaders()) } } xhr.open("get", "/api/data", true) xhr.setRequestHeader("SomeKey", "SomeValue") xhr.send(null)
FormData
XMLHttpRequest 2級(jí)定義了FormData類型為序列化表單、創(chuàng)建與表單格式相同的數(shù)據(jù)、用于XHR傳輸提供便利。FormData提供append()方法可以直接添加數(shù)據(jù),該方法接收兩個(gè)參數(shù)鍵和值。FormData的構(gòu)造函數(shù)可以不傳參數(shù),也可以直接傳入1個(gè)表單元素。傳入表單元素之后會(huì)利用該表單元素的數(shù)據(jù)來(lái)向FormData對(duì)象預(yù)先填入鍵值對(duì)。下面是簡(jiǎn)單示例。
var form = document.getElementById('myForm') var data = new FormData(form) data.append('someKey', 'someValue') var xhr = new XMLHttpRequest() xhr.onreadystatechange = function() { if (xhr.readyState === 4) { console.log(xhr.responseText) } } xhr.open('post', '/api/upload', true) xhr.send(data)
跨域資源共享
通過(guò)XHR實(shí)現(xiàn)Ajax通信會(huì)遇到一個(gè)限制,即跨域安全策略??缬虬踩呗韵拗屏恕跋嗤蛎?、相同端口、相同協(xié)議”,當(dāng)XHR想要訪問(wèn)限制之外的資源就會(huì)引發(fā)安全錯(cuò)誤。CORS(Cross-Origin Resource Sharing),跨域資源共享,其思想是通過(guò)使用自定義HTTP頭部讓瀏覽器與服務(wù)器進(jìn)行溝通從而決定請(qǐng)求或者響應(yīng)的成功與失敗,需要瀏覽器和服務(wù)器同時(shí)支持才能實(shí)現(xiàn)正常的訪問(wèn)。目前大部分瀏覽器已經(jīng)支持了CORS,所以寫(xiě)起代碼跟普通的同域資源訪問(wèn)幾乎一樣,就只是把URL用絕對(duì)路徑表示。因此,要實(shí)現(xiàn)跨域的關(guān)鍵還是在服務(wù)器,具體如何實(shí)現(xiàn)本文不深入討論。下面是前端js的簡(jiǎn)單示例。
var xhr = new XMLHttpRequest() xhr.onreadystatechange = function() { if (xhr.readyState === 4) { console.log(xhr.responseText) } } xhr.open('get', 'http://www.otherserver.com/api/data', true) xhr.send(null)
JSONP
JSONP(JSON with padding)是應(yīng)用JSON實(shí)現(xiàn)跨域資源訪問(wèn)的一種方法。JSONP由兩部分內(nèi)容組成:回調(diào)函數(shù)和JSON數(shù)據(jù)。前面說(shuō)過(guò),XHR請(qǐng)求會(huì)遇到跨域安全策略的限制,但是HTML中的script標(biāo)簽則不會(huì)有這個(gè)限制,我們可以通過(guò)script標(biāo)簽引用不同域里面的js文件。JSONP便是鉆了這個(gè)空子,它通過(guò)動(dòng)態(tài)創(chuàng)建script元素,然后把src指向其他域的URL從而實(shí)現(xiàn)加載其他域的資源,然后通過(guò)回調(diào)函數(shù)來(lái)處理加載得到的數(shù)據(jù)。下面是一個(gè)簡(jiǎn)單示例。
function handler(res) { console.log(res) } var script = document.createElement('script') script.src = 'http://www.otherserver.com/api/data/?callback=handler' document.body.insertBefore(script, document.body.firstChild)
上述代碼指定了動(dòng)態(tài)創(chuàng)建的script元素的src為另一個(gè)域名下面的/api/data,然后指明回調(diào)函數(shù)為handler。將script插入到DOM里面之后會(huì)向?qū)?yīng)的URL加載數(shù)據(jù),完成之后會(huì)將得到的JSON數(shù)據(jù)解析成一個(gè)對(duì)象并調(diào)用handler進(jìn)行處理。
JSONP是實(shí)現(xiàn)跨域訪問(wèn)的一種簡(jiǎn)單的方法,不過(guò)也存在一些安全問(wèn)題,例如請(qǐng)求的其他域的URL響應(yīng)給你一段惡意代碼。JSONP還有一個(gè)問(wèn)題,script標(biāo)簽引用的是js,json由于被js所支持所以也可以引用,因此在請(qǐng)求其他域的URL時(shí)需要確認(rèn)它是否以json格式進(jìn)行響應(yīng),而不是XML。
Comet
Ajax是一種從網(wǎng)頁(yè)向服務(wù)器請(qǐng)求數(shù)據(jù)的技術(shù),而Comet與之相反,它是從服務(wù)器向網(wǎng)頁(yè)推送數(shù)據(jù)的技術(shù),適用于實(shí)時(shí)性要求比較高的應(yīng)用。實(shí)現(xiàn)Comet的方式有兩種:長(zhǎng)輪詢和流。在說(shuō)長(zhǎng)輪詢之前先說(shuō)一下短輪詢,它的思路很簡(jiǎn)單,就是客戶端使用定時(shí)器,每隔一定的時(shí)間間隔就向服務(wù)器發(fā)送Ajax請(qǐng)求看看有沒(méi)有數(shù)據(jù)更新,這個(gè)時(shí)間間隔一般很小。長(zhǎng)輪詢同樣也是客戶端不斷向服務(wù)器發(fā)送請(qǐng)求,不同的是,客戶端不需要按照時(shí)間間隔不斷地發(fā)送請(qǐng)求,而是發(fā)起1個(gè)請(qǐng)求到服務(wù)器之后,客戶端和服務(wù)器之間的HTTP連接保持打開(kāi),直到服務(wù)器有數(shù)據(jù)更新就通過(guò)這個(gè)連接向客戶端響應(yīng)數(shù)據(jù),然后再關(guān)閉這個(gè)HTTP連接。關(guān)閉之后瀏覽器再發(fā)起一個(gè)新的連接繼續(xù)重復(fù)前面的過(guò)程。相比短輪詢,長(zhǎng)輪詢發(fā)起的HTTP連接次數(shù)更少了,不過(guò)如果HTTP連接長(zhǎng)時(shí)間保持開(kāi)放也是在占用服務(wù)器的資源。
第二種實(shí)現(xiàn)Comet的方式是基于HTTP流,客戶端向服務(wù)器發(fā)起1個(gè)HTTP連接,全程保持這個(gè)連接打開(kāi),客戶端周期性地通過(guò)這個(gè)連接向服務(wù)器獲取數(shù)據(jù)查看更新。
SSE
SSE(Server-Send Events),服務(wù)器發(fā)送事件,是一種實(shí)現(xiàn)Comet交互的瀏覽器API,支持輪詢也支持HTTP流。SSE API用于創(chuàng)建到服務(wù)器的單向連接,服務(wù)器通過(guò)這個(gè)連接可以發(fā)送任意數(shù)量的數(shù)據(jù)給客戶端。服務(wù)器響應(yīng)的MIME類型為text/event-stream。下面是SSE的JavaScript API的簡(jiǎn)單示例。
var source = new EventSource("/api/events") source.onmessage = function(event) { console.log(event.data) }
如上面代碼所示,要向服務(wù)器預(yù)定事件流獲取服務(wù)器發(fā)送的數(shù)據(jù),首先創(chuàng)建EventSource對(duì)象,然后在message事件觸發(fā)的時(shí)候進(jìn)行處理。服務(wù)器發(fā)送的數(shù)據(jù)以字符串形式保存在event.data中。EventSource對(duì)象會(huì)保持與服務(wù)器的活動(dòng)連接,如果中間斷開(kāi)會(huì)重新連接,如果要真正地?cái)嚅_(kāi)連接可以通過(guò)調(diào)用close()方法來(lái)實(shí)現(xiàn)。EventSource的message事件會(huì)在從服務(wù)器收到新事件的時(shí)候觸發(fā),除了message事件之外它還有另外2個(gè)事件open和error,open事件在建立連接的時(shí)候觸發(fā),error事件在無(wú)法建立連接的時(shí)候觸發(fā)。
Web Sockets
Web Sockets是一種與服務(wù)器進(jìn)行全雙工雙向通信的通道。Web Sockets不適用HTTP協(xié)議,而前面說(shuō)的Ajax和Comet都是使用HTTP協(xié)議。篇幅關(guān)系本文對(duì)Web Sockets不作討論。
總結(jié)
Ajax實(shí)現(xiàn)在不加載頁(yè)面的情況下向服務(wù)器請(qǐng)求數(shù)據(jù),提升網(wǎng)頁(yè)的用戶體驗(yàn)。實(shí)現(xiàn)Ajax技術(shù)的XHR會(huì)遇到跨域安全策略的限制,通過(guò)CORS解決跨域問(wèn)題需要瀏覽器和服務(wù)器兩端的配合。JSONP是一種實(shí)現(xiàn)跨域訪問(wèn)的”小技巧“但也是存在一些問(wèn)題。Comet對(duì)Ajax進(jìn)行了拓展,讓服務(wù)器能夠?qū)崟r(shí)向?yàn)g覽器推送數(shù)據(jù),但從實(shí)現(xiàn)來(lái)看不管是輪詢還是HTTP流,都是瀏覽器先向服務(wù)器發(fā)起請(qǐng)求連接。Web Sockets的全雙工雙向通信也有其特色,以后有時(shí)間可以繼續(xù)了解。
以上就是本文的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,同時(shí)也希望多多支持腳本之家!
相關(guān)文章
使用js判斷數(shù)組中是否包含某一元素(類似于php中的in_array())
這篇文章主要是對(duì)使用js判斷數(shù)組中是否包含某一元素(類似于php中的in_array())需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助2013-12-12JS?解決Cannot?set?properties?of?undefined的問(wèn)題
遇到這樣問(wèn)題當(dāng)前的是當(dāng)前對(duì)象或者數(shù)組是undefined,但是卻用來(lái)引用屬性或者索引,遇到這樣的問(wèn)題如何解決呢,下面通過(guò)本文給大家介紹JS?如何解決Cannot?set?properties?of?undefined,需要的朋友可以參考下2024-01-01原生JS操作網(wǎng)頁(yè)給p元素添加onclick事件及表格隔行變色
原生JS操作網(wǎng)頁(yè),給網(wǎng)頁(yè)中的所有p元素添加onclick事件,使一個(gè)特定的表格隔行變色等等,感興趣的朋友可以參考下2013-12-12Bootstrap實(shí)現(xiàn)模態(tài)框效果
這篇文章主要為大家詳細(xì)介紹了Bootstrap實(shí)現(xiàn)模態(tài)框效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-09-09JavaScript canvas基于數(shù)組生成柱狀圖代碼實(shí)例
這篇文章主要介紹了JavaScript canvas基于數(shù)組生成柱狀圖代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03