传统中网站实现实时推送往往是一件比较难的事情,因为HTTP是无状态的,请求只能是由客户端发送,服务器处理这些请求,服务器是被动的,服务器有变化却没有办法将数据主动传输给客户端,传统中解决这种问题主要以下方法:
1、轮询
设定一个定时器发送Ajax请求,当检测数据是否发生变化,它的代码可能如下:
function query() {
var xhr = new new XMLHttpRequest();
xhr.open('GET','/data', true);
xhr.load = function(e) {
if(e.status == 200) {
var ret = JSON.parse(e.response);
if(ret.changed){
//........
} else{
setTimeout(query, 1000);
}
}
}
xhr.send();
}
query();
轮询的缺点非常明显,首先客户端需要发送大量请求,而服务端需要处理大量请求,这些资源的消耗其实很大一部分都是没有必要的,而且应用的实时性与轮询设定的时间有关。
2、长轮询
长轮询主要利用的是HTTP协议的长连接,当客户端发送一个ajax请求后,服务器查询数据是否有更改,如果有更改就立即返回,没有就hold住请求不返回,这样客户端就会一直处于pending状态,服务器端保持不断查询数据是否更新,一旦更新就返回,这样就做到了数据的实时传递。
显然长轮询消耗的客户端资源较少,但是服务端要hold一个连接同样要消耗部分资源。
这些解决方案都是基于HTTP协议的,而HTTP协议每次请求都需要带上报文头,这需要消耗一定的资源,对于实时应用来说这部分资源算是不小的开销了,而WebSocket将传统的套接字概念引入web,这样在web建立全双工通信通道成为了可能。
WebSocket客户端
WebSocket是一种新的通信协议,新建一个WebSocket协议时需要制定连接的地址,以ws开头,同样与http类似,安全连接以wss开头,客户端建立一个连接只需要调用WebSocket()构造函数即可,这个函数接受一个url参数和一个可选的子协议参数,子协议参数可以是字符串或者数组:
var socket = new WebSocket('wss://localhost/chat', ['soap', 'xmpp']);
一个WebSocket实例主要有以下属性:
- url:实例的url地址
- protocol:创建实例时传递的子协议,没有则是空字符串,有的话为传递的第一个协议的字符串
- extensions:服务器选定的拓展
- readyState:连接的当前状态,有四种状态:
CONNECTION: 连接还没开启,对应的readyState值为0
OPEN: 连接已经建立,可以开始通信了,对应的readyState值为1
CLOSING: 连接正在关闭的过程中,对应的readyState值为2
CLOSED: 连接已经关闭,对应的readyState值为3
因此判断连接当前的状态可以判断readyState的值,或者是与状态比对:
if(socket.readyState === 1) {
console.log('连接已经打开');
}
// or
if(socket.readyState === WebSocket.OPEN){
console.log('连接已经打开');
}
- binaryType:二进制传输的内容的类型
- onclose:关闭连接的事件监听器
- onerror:错误发生的事件监听器
- onmessage:消息到达的事件监听器,事件监听器中的回调函数的事件e中的data属性代表数据内容
socket.onmessage = function(e){
console.log('server send ' + e.data);
}
- onopen:连接打开的事件监听器(因为这个连接是异步的)
一个WebSocket实例主要有以下方法:
- close:用来关闭连接
socket.close();
- send:用来向服务器发送数据:
socket.send('something from client');
网友评论