连接池
我们公司在路由和交换机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'});
参考资料:
《javascript权威指南》