除了依赖浏览器处理缓存之外,还可以用手工方法直接存储那些从服务器收到的响应报文。可将响应报文存放在一个对象中,以URL为键值对它进行索引。以下是一个XHR封装,它首先检查一个URL此前是否被取用过。
var localCache={};
function xhrRequest(url,callback){
if(localCache[url]){
callback.success(localCache[url]);
return;
}
var req=createXhrObject;
req.onerror=function{
callback.error;
};
req.onreadystatechange=function{
if(req.readyState==4){
if(req.responseText===''||req.status=='404'){
callback.error;
return;
}
localCache[url]=req.responseText;
callback.success(req.responseText);
}
};
req.open("GET",url,true);
req.send(null);
}
当然,设置一个Expires头是更好的解决方案,实现起来比较容易,而且其缓存内容可以跨页面或跨对话。而一个手工缓存可以利用程序废止缓存内容并获取新的数据。设想一种情况,为每个请求缓存数据,用户可能触发某些动作导致一个或多个响应报文作废。在这种情况下从缓存中删除报文十分简单:
delete localCache['/user/friendlist/'];
delete localCache['/user/contactlist/'];
本地缓存也可很好地工作于移动设备上。此类设备上的浏览器缓存小或根本不存在,手工缓存成为避免不必要请求的最佳选择。
值得注意的是,在大部分XHR技术中要用到流功能。通过监听readyState=3,可以在一个大的响应报文没有完全接收之前就开始解析它,这时可以实时处理报文片断。这也是MXHR能够大幅度提高性能的原因之一。不过大多数JavaScript库不允许直接访问readystatechange事件,这意味着必须等待整个响应报文接收完才能使用它。
直接使用XMLHttpRequest对象并非像看起来那么不好。除一些个别行为之外,所有主流浏览器的最新版本均以同样方式支持XMLHttpRequest对象,均可访问不同的readyState。要支持老版本的IE,只需要多加几行代码。下面例子中的函数返回一个XHR对象,可以直接调用这个对象。
function createXhrObject{
var msxml_progid=['MSXML2.XMLHTTP.6.0',
'MSXML3.XMLHTTP',
'Microsoft.XMLHTTP',
'MSXML2.XMLHTTP.3.0'];
var req;
try{
req=new XMLHttpRequest;
}catch(e){
for(var i=0,len=msxml_progid.length;i<len;++i){
try{
req=new ActiveXObject(msxml_progid[i]);
break;
}catch(e2){
}
}
}finally{
return req;
}
}
此函数首先尝试支持readyState=3的XMLHttpRequest,然后回落到那些不支持此状态的版本中。直接操作XHR对象减少了函数开销,进一步提高了性能。只是放弃使用Ajax库,可能会在极少数的浏览器上遇到一些问题。