JavaScript实现与Web通信的多种方案详解
本文详细解析了JavaScript实现Web通信的多种技术,包括轮询、长轮询、数据流、WebSocket、EventSource以及基于插件的Flash和Java Applet方案。文章对比了各方案的优缺点、浏览器兼容性及资源消耗,并提供了相应的代码示例与后端处理建议,帮助开发者根据实际需求选择最合适的通信方式。
前言与背景
Web通信是一个涵盖面极广的话题,涉及的技术领域众多。鉴于近期对JavaScript中Web通信相关知识的深入学习,特此进行总结。文中可能存在理解偏差或表述不清之处,恳请指正。
一、前言
1. Comet技术
浏览器作为Web应用的前端,其内置处理能力相对有限。浏览器功能的升级依赖于客户端软件的更新,而客户端浏览器的多样性也在一定程度上阻碍了新技术的普及。在Web应用中,浏览器的核心职责是发送请求、解析服务器返回的数据,并以特定的样式进行展示。AJAX技术的出现是浏览器技术发展的里程碑,它通过异步请求提升了单用户操作的响应速度。然而,Web本质上是多用户系统,对任何用户而言,服务器可视为另一个用户。现有的AJAX技术难以解决在多用户Web应用中实时向客户端推送更新信息的问题,这可能导致用户基于过时信息进行操作。同时,AJAX的应用使得后台数据更新更加频繁成为可能。
随着互联网的发展,各类Web应用层出不穷,包括网站监控、即时报价、即时通讯系统等。为了提供更好的用户体验,服务器需要频繁向客户端推送信息。开发者通常采用基于AJAX的长轮询方式,或者基于iframe及htmlfile的流处理方式。此外,部分应用需要在客户端安装Java applet或Flash等插件,以支持性能更优的“推”信息功能。
2. HTTP协议中的长、短连接
短连接的操作流程为:建立连接——数据传输——关闭连接,该过程重复进行。长连接的操作流程为:建立连接——数据传输……(保持连接)……数据传输——关闭连接。
长连接与短连接的主要区别在于客户端和服务器采取的关闭策略不同。短连接在建立连接后仅进行一次数据传输即关闭连接;而长连接在建立连接后会进行多次数据传输,直到明确关闭连接(通过Connection: closed头部字段标识)。
Web通信核心机制
二、web 通信
首先需要明确xhr的readystate各种状态。
| 属性 | 描述 |
|---|---|
| onreadystatechange | 存储函数(或函数名),每当 readyState 属性改变时,就会调用该函数。 |
| readyState | 存有 XMLHttpRequest 的状态。从 0 到 4 发生变化。 0: 请求未初始化 1: 服务器连接已建立 2: 请求已接收 3: 请求处理中 4: 请求已完成,且响应已就绪 |
| status | 200: "OK" 404: 未找到页面 |
1.轮询
轮询是一种“拉”取信息的工作模式。通过设置定时器,定时询问服务器是否有新信息,每次建立连接传输数据后,链接会关闭。
前端实现:
var polling = function(url, type, data){
var xhr = new XMLHttpRequest(),
type = type || "GET",
data = data || null;
xhr.onreadystatechange = function(){
if(xhr.readyState == 4) {
receive(xhr.responseText);
xhr.onreadystatechange = null;
}
};
xhr.open(type, url, true);
//IE的ActiveXObject("Microsoft.XMLHTTP")支持GET方法发送数据,
//其它浏览器不支持,已测试验证
xhr.send(type == "GET" ? null : data);
};
var timer = setInterval(function(){
polling();
}, 1000);
在轮询过程中,若因网络原因导致上一个xhr对象尚未传输完毕,而定时器已触发下一次询问,上一次的传输是否仍会在队列中,此问题未深入探究。如有兴趣,可自行编写一个ajax请求管理队列。
2.长轮询(long-polling)
长轮询并无特殊之处,即在xhr对象关闭连接时立即重新建立连接。代码如下:
var longPoll = function(type, url){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
// 状态为 4,数据传输完毕,重新连接
if(xhr.readyState == 4) {
receive(xhr.responseText);
xhr.onreadystatechange = null;
longPoll(type, url);
}
};
xhr.open(type, url, true);
xhr.send();
}
只要服务器断开连接,客户端立即重新连接,使其无休息片刻,这就是长轮询。
3.数据流
数据流方式是在连接断开之前,即readystate状态为3时接收数据。但难点在于,由于数据正在传输,获取的xhr.response可能只是部分数据。因此,最好定义一个数据传输协议,例如前2个字节表示字符串长度,然后只获取该长度的内容,接着改变游标位置。
假设数据格式为:data splitChar,其中data为数据内容,splitChar为数据结束标志(长度为1)。那么传输的数据内容为:data splitChar data splitChar data splitChar...。
var dataStream = function(type, url){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
// 状态为 3,数据接收中
if(xhr.readyState == 3) {
var i, l, s;
s = xhr.response; //读取数据
l = s.length; //获取数据长度
//从游标位置开始获取数据,并用分割数据
s = s.slice(p, l - 1).split(splitChar);
//循环并操作数据
for(i in s) if(s[i]) deal(s[i]);
p = l; //更新游标位置
}
// 状态为 4,数据传输完毕,重新连接
if(xhr.readyState == 4) {
xhr.onreadystatechange = null;
dataStream(type, url);
}
};
xhr.open(type, url, true);
xhr.send();
};
上述代码存在缺陷,当readystate为3时可以获取数据,但此时获取的数据可能只是整体数据的一部分,后半部分无法获取。readystate在数据传输完毕前不会改变,即它不会继续接收剩余数据。我们可以定时监听readystate,如下例所示。
这种处理方式不算复杂,但存在兼容性问题。上述轮询和长轮询所有浏览器均支持,因此未编写IE兼容代码。然而,低版本IE不允许在readystate为3时读取数据,因此必须采用其他方式实现。
在ajax进入Web专题之前,我们已经拥有一个工具,即iframe,利用iframe同样可以异步获取数据。对于低版本IE,可以使用iframe来接收数据流。
if(isIE){
var dataStream = function(url){
var ifr = document.createElement("iframe"), doc, timer;
ifr.src = url;
document.body.appendChild(ifr);
doc = ifr.contentWindow.document;
timer = setInterval(function(){
if(ifr.readyState == "interactive"){
// 处理数据,同上
}
// 重新建立链接
if(ifr.readyState == "complete"){
clearInterval(timer);
dataStream(url);
}
}, 16);
};
};
定时监听iframe的readystate变化以获取数据流,但上述处理方式仍存在缺陷。数据流实现“服务器推”数据的原理是:文档(数据)尚未加载完毕时,浏览器从服务器获取数据以完成文档加载。我们利用这一点,向浏览器发送部分数据。因此,上述利用iframe获取数据的方式会使浏览器一直处于加载状态,标题栏的圆圈持续转动,鼠标状态也显示为loading,体验不佳。幸运的是,IE提供了HTMLFile对象,该对象相当于内存中的Document对象,可解析文档。因此,我们创建一个HTMLFile对象,在其中放置一个IFRAME以连接服务器。这样,各种浏览器均可支持。
if(isIE){
var dataStream = function(url){
var doc = new ActiveXObject("HTMLFile"),
ifr = doc.createElement("iframe"),
timer, d;
doc.write("<body/>");
ifr.src = url;
doc.body.appendChild(ifr);
d = ifr.contentWindow.document;
timer = setInterval(function(){
if(d.readyState == "interactive"){
// 处理数据,同上
}
// 重新建立链接
if(d.readyState == "complete"){
clearInterval(timer);
dataStream(url);
}
}, 16);
};
};
4.websocket
WebSocket是前端的一项强大工具。AJAX技术已使用多年,相关技术成熟,但实现数据拉取仍十分困难,从上述代码中可见各种兼容性及细节处理问题。自WebSocket出现后,一切变得简单,仿佛“一口气上五楼”。
var ws = new WebSocket("ws://www.example.com:8888");
ws.onopen = function(evt){};
ws.onmessage = function(evt){
deal(evt.data);
};
ws.onclose = function(evt){};
//ws.close();
新建一个WebSocket实例即可,ws://是WebSocket的连接协议,8888为端口号。onmessage中提供了data属性,非常方便。
5.EventSource
HTML5提供的EventSource是接收服务器推送信息的极其简洁的函数。
new EventSource("test.php").onmessage=function(evt){
console.log(evt.data);
};
其简洁程度与WebSocket相当,但需注意,test.php输出的数据流应为特殊的MIME类型,即"text/event-stream"。若不设置,将直接抛出异常。
6.ActionScript
情非得已时不要考虑第六种方式。虽然兼容性最好,但若不懂ActionScript,出现bug时无法调试。
具体实现方法:在HTML页面中嵌入使用XMLSocket类的Flash程序。JavaScript通过调用此Flash程序提供的套接口接口与服务器端的套接口进行通信。JavaScript在收到服务器端以XML格式传送的信息后,可轻松控制HTML页面的内容显示。
7.Java Applet套接口
该方式原理与Flash类似,但因不熟悉,不再详述。
后端处理与方案对比
三、后端处理方式
本文主要总结JavaScript的各种通讯方式,后端配合Node.js处理,效果显著。
var conns = new Array();
var ws = require("websocket-server");
var server = ws.createServer();
server.addListener("connection", function(connection){
console.log("Connection request on Websocket-Server");
conns.push(connection);
connection.addListener('message',function(msg){
console.log(msg);
for(var i=0; i<conns.length; i++){
if(conns[i]!=connection){
conns[i].send(msg);
}
}
});
});
server.listen(8888);
以下是一个PHP测试demo。
header('Content-Type:text/html; charset=utf-8');
while(1){
echo date('Y-m-d H:i:s');
flush();
sleep(1);
};
四、web 通信方式利弊分析
- 轮询:这种方式技术含量最低,操作最方便,但及时性不强。缩短定时器间隔时间可稍作改善。
- 长轮询:算是较好的Web通讯方式,但每次断开连接消耗服务器资源较多,客户端影响不大。
- 数据流:与长轮询不同之处在于接收数据的时间点,数据流在readystate为3时接收。低版本IE兼容性较差,处理略麻烦,且需自行设计数据传输协议。不过,其对资源的消耗比上述几种方式更可观。
- WebSocket和EventSource:两者均为利器,但支持浏览器较少,令人遗憾。
- ActionScript和Java Applet:两者均需在客户端安装插件,分别是Flash插件和Java插件。前端开发者通常不熟悉这些技术,若无封装良好的库,建议不使用。
五、参考资料
http://www.ibm.com/developerworks/cn/web/wa-lo-comet/ Comet:基于 HTTP 长连接的“服务器推”技术
http://blog.csdn.net/yankai0219/article/details/8208776 HTTP协议中长连接、短连接
http://www.web-tinker.com/ comet系列文章
到此这篇关于JavaScript实现与web通信的方法详解的文章就介绍到这了,更多相关JavaScript与web通信内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!
JavaScript闭包与类(Class)的区别及适用场景对比
2026-11-05 15:48:57
JavaScript入门要学ES6吗?let与箭头函数等新特性解析
2026-11-05 14:49:16
JavaScript 8种数据类型详解:基本类型与引用类型的区别
2026-11-05 14:25:15
怎么在JavaScript中使用async/await优化Ajax异步流程
2026-11-05 13:56:15
JavaScript replace回调函数实现动态正则替换逻辑
2026-11-05 13:52:13
