一、简史
IE5.5最早实现XHR,需要通过ActiveXObject创建xhr实例,直到IE7才定义了XMLHttpRequest对象。IE5.5实现XHR之后,其他浏览器紧随其后实现了XHR,直接命名为XMLHttpRequest。早期的XHR能力有限:只能传输文本,上传能力有限,而且不能跨域。为了解决这些问题,W3C于2008年发布了“XMLHttpRequest Level 2”草案。增强了XHR的能力:
(1)支持请求超时。xhr.timeout = 3000
(2)支持传输二进制和文本数据
(3)支持应用重写媒体类型和编码响应
(4)支持监控每个请求的进度事件
(5)支持有效的文件上传
(6)支持安全的跨来源请求
三、通过XHR下载数据
XHR既可以传输文本数据,也可以传输二进制数据。浏览器可以自动为各种原生数据类型提供编码和解码服务,因此在直接将数据传给XHR时就已经编码/解码好了。XHR自动解码支持的数据类型:
(1)ArrayBuffer
固定长度的二进制数据缓冲区
(2)Blob
二进制大对象或不可变数据
(3)Document
html或xml
(4)JSON
js对象
(5)Text
纯文本
浏览器可根据http首部content-type判断适当的数据类型。应用也可在发起XHR请求时显示重写数据类型:
var xhr = new XMLHttpRequest(); xhr.open('GET', '/images/photo.webp'); xhr.responseType = 'blob';// 将返回类型设置为Blob xhr.onload = function(){ if(this.status == 200){ var img = document.createElement('img'); img.src = window.URL.createObjectURL(this.response);//基于响应创建唯一对象URI img.onload = function(){ window.URL.revokeObjectURL(this.src);// 图片加载完成立即释放对象 }; document.body.appendChild(img); } }
五、XHR流式数据传输
流的应用场景很重要,可惜到现在为止没有API来实现XHR流
(1)上传时,send方法只接受完整的载荷
(2)response、responseText、responseXML属性也不是为流设计的
上传时只能通过将文件切分,然后用多个xhr请求迭代上传。
流式下载得到了浏览器有限的支持:
var xhr = new XMLHttpRequest();
xhr.open('GET', '/stream');
xhr.seenBytes = 0;
xhr.onreadstatechange = function(){
if(xhr.readyState > 2){
var newData = xhr.responseText.substr(xhr.seenBytes);
// TODO 处理newData
xhr.seenBytes = xhr.responseText.length;
}
};
xhr.send();
缺陷:
需要手工跟踪偏移量,手工切分数据:responseText缓冲了完整的响应,当前请求完成之前无法释放内存。
只能读取文本数据,无法读取二进制数据。
浏览器兼容性:允许读取的数据类型不一致,有的允许text/html,有的只允许application/x-javascript
总之,XHR流实现起来麻烦而效率低,无法在生产环境下使用。
六、实时通知与交付
(1)通过XHR实现定时轮询。客户端定时发起XHR请求,如果服务端有新数据,返回新数据,没有返回空响应。难点在于,最佳的轮询间隔很难把握。需要在效率与消息延迟之间做权衡。
(2)通过XHR实现长轮询。定时轮询很可能造成大量没必要的空检查。可以做这样的改进:没有数据的时候不再立即返回空数据,而是把链接保持一段时间。
(3)WebSocket。HTML5新增的特性,可考虑在高版本浏览器下实现。
目前还是长轮询的解决方案使用的较为广泛。
七、参考资料
《web性能权威指南》
《JavaScript高级程序设计》