前端实现即时通讯的几种方式
前言:由于http协议是请求/响应式的, 每一个 http响应都是由一个对应的 http请求产生的; http 协议是无状态的,多个 http 请求之间是没有关系的。常见的有股票数据echart图实时更新、基金行业批处理某个基金查看全局的无感刷新。主要是以下几种方式
短轮询
定义:其实就是普通的轮询。指在特定的的时间间隔(如每1秒),由浏览器对服务器发出请求,然后由服务器返回最新的数据给客户端的浏览器。
var xhr = new XMLHttpRequest();
setInterval(function(){
xhr.open('GET','/user');
xhr.onreadystatechange = function(){
//处理所有要得逻辑
};
xhr.send();
},1000)
优点 | 缺点 |
---|---|
程序逻辑易于实现 | ①浪费宽带/服务器资源 ②预期结果难以把控(异步请求多次调用无法保证顺序)③难于维护 |
长轮询
定义:客户端向服务器发送请求,服务器接到请求后hold住连接,直到有新消息才返回响应信息并关闭连接,客户端处理完响应信息后再向服务器发送新的请求。
function ajax(){
var xhr = new XMLHttpRequest();
xhr.open('GET','/user');
xhr.onreadystatechange = function(){
ajax();
};
xhr.send();
}
优点 | 缺点 |
---|---|
在无消息的情况下不会频繁的请求,耗费资源小 | 服务器hold连接会消耗资源,返回数据顺序无保证,难于管理维护。 |
Web Socket
定义:Websocket是基于HTTP协议的。浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
优点 | 缺点 |
---|---|
请求响应快,不浪费资源。 | 主流浏览器支持的Web Socket版本不一致;服务端没有标准的API |
特点:
- 建立在 TCP 协议之上,服务器端的实现比较容易。
- 与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
- 数据格式比较轻量,性能开销小,通信高效。
- 可以发送文本,也可以发送二进制数据。
- 没有同源限制,客户端可以与任意服务器通信。
- 协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。
//服务器端
var Server = require('ws').Server;
var wss = new Server({
port:2000
});
wss.on('connection',function(ws){
ws.on('message',function(data){
ws.send('你好,客户端,我是服务器!');
console.log(data);
})
});
//node客户端
var WebSocket = require('ws');
var socket = new WebSocket('ws://localhost:2000/');
socket.on('open',function(){
socket.send('你好,服务器,我是客户端');
});
socket.on('message',function(event){
console.log(event);
})
//html客户端(注:浏览器客户端与node客户端只需要一种)
<script>
var socket = new WebSocket('ws://localhost:2000/'); //http协议对应ws https对应wss
socket.onopen = function(){
console.log('已经开始连接')
};
socket.onmessage = function(event){
console.log(event.data)
}
</script>
SSE
定义:Server-Sent Events:简称SSE技术,也是前端es5支持的一种基于http协议的服务器推送技术。
Web Socket | SSE |
---|---|
①全双工通道,可以双向通信,功能更强 | ①单向通道,只能服务器向浏览器端发送 |
②新的协议,需要服务器端支持 | ②部署在 HTTP协议之上的,现有的服务器软件都支持 |
③较重的协议,相对复杂 | ③轻量级协议,相对简单 |
④需要额外部署 | ④默认支持断线重连 |
⑤支持CORS | ⑤不支持CORS,支持自定义发送的数据类型 |
const SSE = new EventSource('/api/v1/sse');
/* This will listen only for events
* similar to the following:
*
* event: notice
* data: useful data
* id: someid
*
*/
SSE.addEventListener("notice", function(e) {
console.log(e.data)
})
/* Similarly, this will listen for events
* with the field `event: update`
*/
SSE.addEventListener("update", function(e) {
console.log(e.data)
})
/* The event "message" is a special case, as it
* will capture events without an event field
* as well as events that have the specific type
* `event: message` It will not trigger on any
* other event type.
*/
SSE.addEventListener("message", function(e) {
console.log(e.data)
})
附带 : 利用DIV模拟<textarea/>
- template代码
<div contenteditable="true" @textInput="Input"></div>
- script标签进行js的事件处理
Input(e) {
// 需要执行的js操作。input事件进行任何的输入都会触发
//data函数定义获取输入框的值为变量:fillBlank
this.fillBlank = e.target.innerHTML
console.log('输入信息',e);
},