在ajax應用中,一般一個頁面要同時發送多個請 求,若是隻有一個XMLHttpRequest對象,前面的請求還未完成,後面的就會把前面的覆蓋掉,若是每次都建立一個新的 XMLHttpRequest對象,也會形成浪費。解決的辦法就是建立一個XMLHttpRequset的對象池,若是池裏有空閒的對象,則使用此對象, 不然將建立一個新的對象。javascript
下面是我最近寫的一個簡單的類:
php
/**
* XMLHttpRequest Object Pool
*
* @author legend <legendsky@hotmail.com>
* @link http://www.ugia.cn/?p=85
* @Copyright www.ugia.cn
*/
var XMLHttp = {
_objPool: [],
_getInstance: function ()
{
for (var i = 0; i < this._objPool.length; i ++)
{
if (this._objPool[i].readyState == 0 || this._objPool[i].readyState == 4)
{
return this._objPool[i];
}
}
// IE5中不支持push方法
this._objPool[this._objPool.length] = this._createObj();
return this._objPool[this._objPool.length - 1];
},
_createObj: function ()
{
if (window.XMLHttpRequest)
{
var objXMLHttp = new XMLHttpRequest();
}
else
{
var MSXML = ['MSXML2.XMLHTTP.5.0', 'MSXML2.XMLHTTP.4.0', 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP'];
for(var n = 0; n < MSXML.length; n ++)
{
try
{
var objXMLHttp = new ActiveXObject(MSXML[n]);
break;
}
catch(e)
{
}
}
}
// mozilla某些版本沒有readyState屬性
if (objXMLHttp.readyState == null)
{
objXMLHttp.readyState = 0;
objXMLHttp.addEventListener("load", function ()
{
objXMLHttp.readyState = 4;
if (typeof objXMLHttp.onreadystatechange == "function")
{
objXMLHttp.onreadystatechange();
}
}, false);
}
return objXMLHttp;
},
// 發送請求(方法[post,get], 地址, 數據, 回調函數)
sendReq: function (method, url, data, callback)
{
var objXMLHttp = this._getInstance();
with(objXMLHttp)
{
try
{
// 加隨機數防止緩存
if (url.indexOf("?") > 0)
{
url += "&randnum=" + Math.random();
}
else
{
url += "?randnum=" + Math.random();
}
open(method, url, true);
// 設定請求編碼方式
setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
send(data);
onreadystatechange = function ()
{
if (objXMLHttp.readyState == 4 && (objXMLHttp.status == 200 || objXMLHttp.status == 304))
{
callback(objXMLHttp);
}
}
}
catch(e)
{
alert(e);
}
}
}
};
html
示例:java
<script type="text/javascript" src="xmlhttp.js"></script>
<script type="text/javascript">
function test(obj)
{
alert(obj.statusText);
}
XMLHttp.sendReq('GET', 'http://www.ugia.cn/wp-data/test.htm', '', test);
XMLHttp.sendReq('GET', 'http://www.ugia.cn/wp-data/test.htm', '', test);
XMLHttp.sendReq('GET', 'http://www.ugia.cn/wp-data/test.htm', '', test);
XMLHttp.sendReq('GET', 'http://www.ugia.cn/wp-data/test.htm', '', test);
alert('Pool length:' + XMLHttp._objPool.length);
</script>
web
demo 下載xmlhttp.jsajax
Permalinkjson
December 22, 2005 @ 7:12 pm數組
大哥哥,你的日誌時間超前了吧,已經在BXNA顯示了一天了。。。瀏覽器
December 22, 2005 @ 7:19 pm緩存
我發現這個問題了,後臺的時間選項改了改,沒管用,帖子時間我也改了。鬱悶
再改,改到21號
December 23, 2005 @ 9:12 am
怎麼在IE下使用有問題呢?
提示64行第5個字符,缺乏標識符字符串或數字
而後提示XMLHttp未定義
在Firefox使用正常
December 23, 2005 @ 9:39 am
源代碼裏有中文的註釋,是ansi的,若是你的網站或ie下選擇編碼爲UTF-8,可能會致使錯誤,你把你ie的編碼改爲gb2312看看,或者去掉文件裏的中文註釋
December 26, 2005 @ 10:48 am
服務器是否是php5的?可能須要設置一下php.ini。
December 27, 2005 @ 5:28 pm
測試自動轉向
December 27, 2005 @ 5:31 pm
測試自動轉向
December 27, 2005 @ 8:12 pm
測試自動跳轉
December 29, 2005 @ 3:57 pm
思路很是好,小弟在下提幾個建議:
一、「對象池」的管理功能須要增強,好比池的容量。
二、「對象池」的內存回收須要增強,好比使用完畢的對象釋放內存。
三、請求最好序列一下,以控制因爲服務器延時或網絡延時致使的先請求的後獲得結果。
四、爲了代碼複用和健壯,回調函數應該驗證是否有效,也就是回調函數應該能夠爲空(能夠缺省)。
December 31, 2005 @ 9:57 am
謝謝「野馬」的建議,有空再完善一下。IE默認有兩個線程的限制,因此池的容量不須要很大。
December 31, 2005 @ 1:11 pm
看 了legend的代碼,才知道啥叫高手。很想請教legend,這些mozilla和ie各自特性和差異的資料從何處得來?由於我花了2個多鐘頭才查到 push和pop是ie5.5之後纔有的;javascript中對象的構造O={:,:,:…}是javascript1.2裏面就有的(所以這樣寫而 不是用new object()或者function objectname(){}應該具備更好的兼容性);以及那個頗有意思的addeventlistener是mozilla的DOM裏面特有的。查到這 些東東,個人文件夾裏面已經堆滿了dom,javascript的相關規範了,並且仍是E文的,這多少讓我有些灰心。還有幾個問題,那個load是否是 mozilla裏面xmlhttprequest的事件?load對應readystate=4,那麼還有沒有0,1,2,3對應的其餘事件?由於我在 www.xmlhttp.cn上面沒有找到這個信息,xmlhttprequest我在mozilla的DOM文檔裏面也沒有找到。另外,那個「IE默認 有兩個線程的限制,因此池的容量不須要很大」這句不太明白。
感謝你的這些文章和代碼,若是可以解答個人這些疑問的話,就更感謝了,呵呵。
敬佩!
December 31, 2005 @ 2:09 pm
PS, 「Content-Type=application/x-www-form-urlencoded; charset=UTF-8″是給服務器看的,xmlhttprequest並不會所以去編碼data中的數據,所以data被send以前,須要手工編 碼。我在IE下面用post試了一下,本身構造了一個form表單在http請求中的形式name1=value1&name2=value2, 若是不事先編碼的話,value中若是有「?」或者漢字之類的字符,就會致使出錯。對於get也有相似的問題。IE下面有encodeURI等幾個函數用 來對字符串編碼,能夠解決這個問題,但這須要瀏覽器版本IE5.5以上(儘管encodeURI系列是ECMAScript標準)。我找到了一個能夠進行 url編碼的腳本,但僅僅是那個unicode和gb2312的對應數組,就一百多K。
想請教legend,是否有比較好的通用的解決方法?謝謝。
December 31, 2005 @ 2:52 pm
回 答hzy:一些瀏覽器方面的差異是我在之前作東西的時候遇到的,因此後面寫代碼的時候能夠去避免這些問題。addeventlistener這個是參考 webfx上的一些代碼。至於mozilla中xmlhttprequest裏的事件,新版本中已經不存在這樣的問題了,老版本未測試。
IE默認同時向一個站點發起的請求是兩個,這個問題是我在作上傳程序的時候遇到的,由於我同時向服務器發送三個請求,但最後一個一直得不到迴應,只有等到前面兩個結束後才能返回結果來。
至於urlencode這個在js裏面用encodeURIComponent這個函數,各類瀏覽器均可以的。「Content-Type= application/x-www-form-urlencoded; charset=UTF-8"這句話是告訴服務器,我發送的數據是urlencode過的。
December 31, 2005 @ 3:32 pm
encodeURIComponent 在IE5.0裏面沒有,文檔上這麼說的,我沒試過,因此結論下得比較武斷。謝謝你耐心細緻的解答。另外再跟你套個近乎,俺也是山東的。山東濟南人。呵呵。 如今在青島讀研,也是26歲。呵呵。剛纔好好看了你的blog一下發現了不少好東東,那個bindow,裏面的圖表功能頗有意思,不過估計只能在IE下面 運行(vml)?
今天很高興,知道我有一個這麼厲害的老鄉。贊一個!
January 12, 2006 @ 12:04 pm
你好,原本想直接copy你的生成xmlhttp對象的代碼,發現有點問題。
在IE下面也能夠手工給window添加名爲XmlHttpRequest的屬性,若是用戶代碼中剛好有這麼一個自定義的屬性,這段代碼就不能返回正確的對象了。也許就正如你所說,代碼還有能夠完善的地方。
PS,看你的代碼有種很high的感受,自由而不放浪,英氣逼人,呵呵。
January 16, 2006 @ 10:29 am
有一個問題,是否能夠給每一個請求指定超時時間,加上超時處理?
January 17, 2006 @ 7:12 pm
很是感謝,你的東東幫了我很大的忙!
January 19, 2006 @ 8:29 pm
我想請教一個關於http://www.yule21.com/info/990.htm
這篇文章說得這個問題,他是用vbscript解決的
我想請問一下用javascript就必定沒有辦法解決了嗎?
盼望答案
April 23, 2006 @ 7:50 pm
爲何blog文章的標題不能複製呢?奇怪
April 29, 2006 @ 12:46 am
爲何每次建立一個xmlHttprequest對象的代價須要考慮呢?即便浪費,不也是浪費clint端的那一點「小小」的性能麼?對整個系統的性能會形成影響麼?做者是否作過性能上的測試,或者有一些經驗數據能夠公佈一下麼?
May 10, 2006 @ 1:30 am
沒有測試過也沒有經驗數據,只是認爲ie每次建立activex對象應該是有些花銷的。我這篇文章的主要目的並非爲了節能,而是爲了併發。
May 10, 2006 @ 1:59 am
??不建立一個池,就不能併發了麼?
還有,xmlhttprequest對象的生命週期有多長?每次從池中取出一個用就能夠麼?
很差意思,新手,不明白的太多,呵呵。
May 10, 2006 @ 2:06 am
不建立也能夠併發,但每次得建立一個新的xmlhttprequest對象。我建立池的目的,就是爲了可以重複利用已經建立的對象。
說到併發,ie默認是每一個站點同時只容許兩個線程的。
這篇文章如今看來,仍是有不少不妥的地方。
May 12, 2006 @ 7:34 pm
真高手,向你學習,頂一個。
May 17, 2006 @ 3:12 am
這東西不錯。那個IE的Ajax緩存狀況之前我遇到過,弄了我很久,到後來才發現IE的ajax會緩存。要是早看到你這篇文章就行了
June 6, 2006 @ 7:22 am
必定要說聲感謝!
November 5, 2006 @ 5:43 pm
用你的代碼在本地運行的時候就出現了狀態代碼是4 的時候回調函數沒反應的狀況,這個是怎麼回事?
November 5, 2006 @ 8:08 pm
o~~ 試驗成功了,以前不知道是哪裏搞錯了,多謝多謝,救急了
December 13, 2006 @ 3:05 pm
很是感謝
December 31, 2006 @ 11:31 am
思 路很好,不過有個問題,IE 解釋腳本的時候是順序執行的,這就是說,他會沿你設計的腳本一步一步走下去! 而 xmlhttpRequst 則是個異步過程,這樣,當下一步腳本調用前,xmlhttpResquest 老是尚未send,因此這個線程池最後也沒起到做用,調用1次sendReq就多建立一個xmlHttpRequest,和沒用池子幾乎沒什麼差異
December 31, 2006 @ 1:02 pm
調用xmlhttprequest就發送了,然後下一次調用的時候,若是前面的都在使用中,會自動創建一個新xmlhttp對象。若是有空閒的對象才會直接使用它。
這個池子並不是爲了效率,而是若是是單一的xmlhttprequest對象,重復調用的話,若是前一個正在發送,後面的就會覆蓋這個對象,那我們的請求就丟失了。
January 12, 2007 @ 3:03 am
謝謝您,您給了很大幫助。
April 21, 2007 @ 6:55 pm
使用中發現了一個問題。當我讀取A完畢,並正確顯示以後,點B,讀取B的內容的時候,B能夠正確顯示,而A又會從新進入讀取狀態,並且始終沒法完成,即staut始終=0。這是什麼呢?怎麼解決?
April 21, 2007 @ 6:59 pm
我代碼作過改動。改動以下:(注:showid是傳入的值,每次都不同,就是顯示的地方。)
onreadystatechange = function ()
{
if (objXMLHttp.readyState 「;
}
if (objXMLHttp.readyState == 4 && (objXMLHttp.status == 200 || objXMLHttp.status == 304))
{
var response = objXMLHttp.responseText;
document.getElementById(showid).innerHTML=response;
April 21, 2007 @ 8:28 pm
要不你就用這個吧: http://www.ugia.cn/?p=122
May 5, 2007 @ 3:58 pm
objXMLHttp.readyState = 0;
在ff中這樣爲對象添加一個屬性能夠嗎?不是應該用addAttribute嗎?
May 12, 2007 @ 12:08 pm
加入隨機數怎麼仍是沒有辦法解決IE的緩存
我用
xmlHttp.abort();
解決了
May 22, 2007 @ 9:08 am
???10)uuu(0)iii(0)ooo(0)000(0)0i(0)0889(0)45677(0)0gk(0)hh(0)u(0)p(0);(0)
ie下 請求頁面獲得的數據會出現如上的亂碼 致使頁面佈局都亂了 請問這是怎麼回事啊 xmlhttp.js裏的中文註釋我已經去掉了
ff下一切正常
May 22, 2007 @ 9:19 am
你頁面 編碼是什麼?
May 22, 2007 @ 9:26 am
html:
New Document
js:
setRequestHeader(’Content-Type’, ‘application/x-www-form-urlencoded; charset=gb2312′);
send(data);
onreadystatechange = function ()
{
if (objXMLHttp.readyState == 4 && (objXMLHttp.status == 200 || objXMLHttp.status == 304))
{
//callback(objXMLHttp);
alert(objXMLHttp.responseText);
}
}
server端:asp
May 22, 2007 @ 9:27 am
server端:asp
May 22, 2007 @ 9:28 am
啊 不讓發代碼啊
server端 asp:
response.charset = 「gb2312″
…
May 22, 2007 @ 9:30 am
客戶端只是發送了一個請求頁面 還沒參數
var u2 = 「txlload/load_team_list.asp」;
XMLHttp.sendReq(’GET’,u2,'’,callback); //打開頁面時 加載分組
May 22, 2007 @ 9:48 am
問題找到了 是建立的xmlhttprequest對象問題
我改爲這樣了:
if(window.XMLHttpRequest){
objXMLHttp = new XMLHttpRequest();
if (objXMLHttp.overrideMimeType) {
objXMLHttp.overrideMimeType(」text/xml」);
}
}
else if (window.ActiveXObject){
try {
objXMLHttp = new ActiveXObject(」Msxml2.XMLHTTP」);
} catch (e) {
try {
objXMLHttp = new ActiveXObject(」Microsoft.XMLHTTP」);
} catch (e) {}
}
}
if (!objXMLHttp) {
window.alert(」can’t create XMLHttpRequest object.」);
return null;
}
ie下也正常了 不過不知道是什麼緣由形成的
August 31, 2007 @ 10:40 am
我比較支持用json,由於rpc有性能問題
做者能告訴一下我QQ和MSN嗎?
UGiA PHP UPLOADER 怎麼實現遠程上傳?我意思是說我網站在A服務器,在A服務器頁面上操做時,怎麼把文件上傳到B服務器上!
August 31, 2007 @ 10:42 am
上面發錯地方了,應該發在 phprpc 那個裏面
August 31, 2007 @ 10:52 am
寫得真好,正想研究下併發的xhr呢,學習了,文檔註釋也很全,可貴啊!
October 24, 2007 @ 8:34 pm
能還能逐行的解釋一下。
剛剛接觸xmlhttprequest這方面的知識。
切盼
個人email:micenote@yahoo.com.cn
December 12, 2007 @ 2:17 pm
正好遇到這種問題,須要解決。這個方法很好用!
December 28, 2007 @ 12:33 am
其實在IE7.0 裏面。
if (window.XMLHttpRequest)
{
var objXMLHttp = new XMLHttpRequest();
}
若是把 var objXMLHttp = new XMLHttpRequest();
//var objXMLHttp=new ActiveXObject(」Microsoft.XMLhttp」); 也是可行的。就是說。在IE7.0 裏面。你先創建那個他就用那個。還有一個問題。就是當我們創建的是var objXMLHttp=new ActiveXObject(」Microsoft.XMLhttp」); 這個時候。responseText 這個東西能夠用responsetext 就是說大小寫均可以的。可是若是是var objXMLHttp = new XMLHttpRequest(); 就必須是responseText。。。。 今天我就是給這個搞了好長時間。鬱悶死了。