ajax连接池和XMLHttpRequest

连接池

我们公司在路由和交换机web界面和后端交互全部采用的是自己封装的ajax组件完成的,组件有点老了,代码风格和其中的某些用法现在看起来都有点不习惯。今天把这个组件的核心部分的ajax连接池记录下来,如果以后有机会,就重新封装一个。

先看看连接池的代码:

 1 var __XmlHttpPool__ ={
 2     m_MaxPoolLength: 10,
 3     m_XmlHttpPool: [],
 4     __requestObject: function () {
 5         var xmlhttp = null;
 6         var pool = this.m_XmlHttpPool;
 7 
 8         for (var i = 0; i < pool.length; ++i) {
 9             if (pool[i].readyState == 4 || pool[i].readyState == 0) {
10                 xmlhttp = pool[i];
11                 break;
12             }
13         }
14 
15         if (xmlhttp == null) {
16             return this.__extendPool();
17         }
18 
19         return xmlhttp;
20     },
21     __extendPool: function () {
22         var xmlhttp = null;
23         xmlhttp = __getXmlhttp(xmlhttp);  //创建新的XHR对象。
24 
25         if ((xmlhttp) && (this.m_XmlHttpPool.length < this.m_MaxPoolLength)) {
26             this.m_XmlHttpPool.push(xmlhttp);
27         }
28         return xmlhttp;
29     }41 };

第9行中通过判断XMLHttpRequest对象的readyState值来获取可以使用的XMLHttpRequest对象(0代表open尚未使用,4代表响应完成),15行则是如果连接池中没有可用的XHR对象,则创建一个新的,并将新的XHR对象放入连接池。由于XHR对象在连接时会消耗资源,如果同时进行的ajax请求的太多会导致页面卡顿甚至浏览器出现未响应情况。所以一般不会同时使用太多的ajax请求。

XMLHttpRequst:

XMLHttpRequest的每个实例都表示一个独立的请求/响应对。由于兼容性问题,一般这样创建XHR对象。

    try {
        xmlhttp = new XMLHttpRequest();
    } catch (e) {
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }

 在创建XHR对象后,发起HTTP请求的下一步是调用该对象的open()方法去指定请求的方法和URL。请求的方法一般为post和get,但是DELETE,HEAD,OPTIONS,PUT也是规范中允许的。其中HEAD在很多浏览器上已经得到支持。但是我对关于HEAD等这些方法的使用代码见的不多,仅仅在《javascript权威指南第六版》的例18-13中见到使用HEAD来实现ajax的跨域。OPEN的第二个参数UEL是请求的主题。这是相对于文档的URL,这个文档包含调用open()的脚步,如果指定绝对URL,协议,主机和端口通常必须匹配所在文档的对于内容:跨域的请求通常会报错。(但是当服务器明确允许跨域请求时,即在服务器响应时会发送合适的CORS,2级XMLHttpRequest规范会允许它。)

 header(‘Access-Control-Allow-Origin: http://arunranga.com‘);

在使用XHR发起http请求时还可以设置请求头,例如POST请求需要"Content-Type"头指定请求主题的MIME类型。对于相同的头调用setRequestHeader()多次,新值不会取代之前指定的值,相反,HTTP请求将包含这个头的多个副本或这个头将指定多个值。由于XMLHttpRequest对象会自动处理cookie、连接时间、字符集和编码判断,所有无法改变Content-Length,Date,Referer,User-Agent,Accept-Charset,keep-Alive,User-Agent,Cookie,Host等。可以指定"Authorization"头,但是通常不用这样做,如果请求一个受到密码保护的URL,可以把用户名和密码作为open()的第四个和第五个参数,则XMLHttpRequest将设置合适的头。open的第三个参数是表示处理HTTP响应是同步还是异步。false表示同步,true表示异步。应当尽量避免使用同步,因为客户端javascript是单线程的,当send()方法阻塞时,它通常会导致整个浏览器UI冻结。当然使用Web Worker除外。

在使用XHR发起HTTP请求的最后一步是指定可选的请求主体并使用send向服务器发送它。GET请求绝对没有主体,使用xmlhttp.sent(null)或直接xmlhttp.send()。POST请求通常拥有主体,同时它应该匹配使用setRequestHeader()指定"Content-Type"头。

  • status和statusText属性以数字和文本的形式返回HTTP状态码。
  • 使用getResponseHeader和getAllResponseHeaders()能查询响应头。XMLHttpRequest会自动处理cookie:它会从getAllResponseHeaders返回的集合中过滤掉cookie。

为了在响应准备就绪是得到通知,必须监听XMLHttpRequest对象上的readstatechange事件。该事件会获得readyState属性

  0  : open()尚未调用

  1  : open()已调用

  2  : 接收到头信息

  3  : 接收到响应主体

  4  :  响应完成

XMLHttpRequst 2:

XHR2有监控HTTP请求上传的事件。在实现这些特性的浏览器中,XMLHttpRequest对象将有upload属性。upload属性值是一个对象,它定义了addEventListener()方法和整个progress事件集合,

比如onproress和onload。注意,upload对象没有定义onreadystatechange属性,upload仅能触发新的事件类型。对于XHR对象xmlhttp,可以设置xmlhttp.onprogress以监控响应的下载进度,并设置xmlhttp.upload.onprogress以监控请求的上传进度。关于upload的使用,可以看如下代码:

1 var xmlhttp = new XMLHttpRequest();
2 xmlhttp.open("POST",url);
3 xmlhttp.upload.progress = function(e){
4   if(e.lengthComputable){
5     console.log(Math.round(e.loaded/e.total*100) + "% Complete");
6   }        
7 }

 XHR增加了timeout属性,可以设置HTTP请求的时限。

 xmlhttp.timeout = 3000;

XMLHttpRequest对象,不仅可以发送文本信息,还可以上传文件。

假定files是一个"选择文件"的表单元素(input[type="file"]),我们将它装入FormData对象。

 var formData = new FormData();
  for (var i = 0; i < files.length;i++) {
   formData.append(‘files[]‘, files[i]);
 }

//...

  xmlhttp.send(formData);

从服务器取回二进制数据,较新的方法是使用新增的responseType属性。

如果服务器返回文本数据,这个属性的值是"TEXT",这是默认值。较新的浏览器还支持其他值,也就是说,可以接收其他格式的数据。

你可以把responseType设为blob,表示服务器传回的是二进制对象。

 1 var xmlhttp = new XMLHttpRequest(); 2   xmlhttp.open(‘GET‘, ‘/path/to/image.png‘); 3   xmlhttp.responseType = ‘blob‘; 

接收数据的时候,用浏览器自带的Blob对象即可。

 1 var blob = new Blob([xhr.response], {type: ‘image/png‘}); 

 

参考资料:

XMLHttpRequest Level 2 使用指南

《javascript权威指南》

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。