剛在ajacn發了個貼,關於為XMLHttpRequest提供一個對象池。或許能幫到你,轉貼如下:
在網上看到了有些同志提到了為AJax的XMLHttpRequest提供一個對象池,也讀了他們給出的實現代碼。感覺不是特別理想,於是模仿apache的commons中的ObjectPool的思路寫了一個簡單的JavaScript版。
望指教:
代碼
function ObjectPool(poolableObjectFactory) {
this._poolableObjectFactory = poolableObjectFactory;
this._idlePool = [];
this._activePool = [];
}
// 從對象池中租借一個對象,如果目前沒有可用的空閒對象則通過poolableObjectFactory創建一個
// 既然是借的,用完記得一定要還哦!
ObjectPool.prototype.borrowObject = function() {
var object = null;
var idlePool = this._idlePool;
var factory = this._poolableObjectFactory;
if (idlePool.length > 0) {
object = idlePool.pop();
}
else {
object = factory.makeObject();
}
if (object != null) {
this._activePool.push(object);
if (factory.activateObject) {
factory.activateObject(object);
}
}
return object;
}
// 歸還一個對象
ObjectPool.prototype.returnObject = function(object) {
function indexOf(array, object) {
for (var i = 0; i < array.length; i++) {
if (array[i] == object) return i;
}
return -1;
}
if (object != null) {
var activePool = this._activePool;
var factory = this._poolableObjectFactory;
var i = indexOf(activePool, object);
if (i < 0) return;
if (factory.passivateObject) {
factory.passivateObject(object);
}
activePool.splice(i, 1);
this._idlePool.push(object);
}
}
// 返回當前激活對象的個數
ObjectPool.prototype.getNuMactive = function() {
return this._activePool.length;
}
// 返回當前空閒對象的個數
ObjectPool.prototype.getNumIdle = function() {
return this._idlePool.length;
}
// 銷毀對象池及其中的所有對象
// 如果對象池中的對象需要析構。那麼必須實現poolableObjectFactory中的destroyObject方法,同時保證ObjectPool的destroy方法在需要的時候被調用到(例如Window的unload事件中)。
ObjectPool.prototype.destroy = function() {
var factory = this._poolableObjectFactory;
function returnObject(object) {
if (factory.passivateObject) {
factory.passivateObject(object);
}
}
function destroyObject(object) {
if (factory.destroyObject) {
factory.destroyObject(object);
}
}
var activePool = this._activePool;
for (var i = 0; i < activePool.length; i++) {
var object = activePool[i];
returnObject(object);
destroyObject(object);
}
var idlePool = this._idlePool;
for (var i = 0; i < idlePool.length; i++) {
var object = idlePool[i];
destroyObject(object);
}
this._idlePool = null;
this._activePool = null;
this._poolableObjectFactory = null;
}
上面代碼中ObjectPool的構造參數poolableObjectFactory的聲明如下:
代碼
// 注意: 這只是說明,不是真正的代碼!
var PoolableObjectFactory = {
makeObject: function() {}, // 創建一個新的對象。(必須聲明)
activateObject: function(object) {}, // 當一個對象被激活時(即被借出時)觸發的方法。(可選)
passivateObject: function(object) {}, // 當一個對象被鈍化時(即被歸還時)觸發的方法。(可選)
destroyObject: function(object) {} // 銷毀一個對象。(可選)
};
結合XMLHttpRequest創建過程的簡陋示例:
代碼
// 聲明XMLHttpRequest的創建工廠
var factory = {
makeObject: function() {
// 創建XMLHttpRequset對象
// 注:這裡的創建方法不夠強壯,勿學!
if (window.ActiveXObject){
return new ActiveXObject("Microsoft.XMLHTTP");
}
else {
return new XMLHttpRequest();
}
},
passivateObject: function(xhr) {
// 重置XMLHttpRequset對象
xhr.onreadystatechange = {};
xhr.abort();
}
};
var pool = new ObjectPool(factory); // 創建對象池
// ......
var xhr = pool.borrowObject(); // 獲得一個XMLHttpRequest對象
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
// ......
pool.returnObject(xhr); // 歸還XMLHttpRequest對象
}
};
xhr.open(method, url, true);
// ......
最後附上JSUnit的測試用例:
代碼
function test_pool() {
var factory = {
counter: 0,
makeObject: function() {
return {id: ++ this.counter};
},
activateObject: function(object) {
object.activated = true;
},
passivateObject: function(object) {
object.activated = false;
},
destroyObject: function(object) {
object.destroyed = true;
}
};
var pool = new ObjectPool(factory);
// borrowObject object1
var object1 = pool.borrowObject();
assertEquals(object1.id, 1);
assertTrue(object1.activated);
assertEquals(factory.counter, 1);
assertEquals(pool.getNuMactive(), 1);
assertEquals(pool.getNumIdle(), 0);
// borrowObject object2
var object2 = pool.borrowObject();
assertEquals(object2.id, 2);
assertTrue(object2.activated);
assertEquals(factory.counter, 2);
assertEquals(pool.getNuMactive(), 2);
assertEquals(pool.getNumIdle(), 0);
// borrowObject object3
var object3 = pool.borrowObject();
assertEquals(object3.id, 3);
assertTrue(object3.activated);
assertEquals(factory.counter, 3);
assertEquals(pool.getNuMactive(), 3);
assertEquals(pool.getNumIdle(), 0);
// returnObject object2
pool.returnObject(object2);
assertFalse(object2.activated);
assertEquals(factory.counter, 3);
assertEquals(pool.getNuMactive(), 2);
assertEquals(pool.getNumIdle(), 1);
// returnObject object3
pool.returnObject(object3);
assertFalse(object3.activated);
assertEquals(pool.getNuMactive(), 1);
assertEquals(pool.getNumIdle(), 2);
// returnObject object1
pool.returnObject(object1);
assertFalse(object1.activated);
assertEquals(pool.getNuMactive(), 0);
assertEquals(pool.getNumIdle(), 3);
// destroy the pool
pool.destroy();
assertTrue(object1.destroyed);
assertTrue(object2.destroyed);
assertTrue(object3.destroyed);
}