为什么需要websocket
因为http协议存在一个缺陷:通信只能由客户端发起
优势:一旦连接建立,后续数据都会以帧序列的形式传输,断开服务前,不需要服务端或者客户端重新发起请求,极大的节省了网络带宽资源的消耗,性能更高,实时性强;
(1)建立在 TCP 协议之上,服务器端的实现比较容易。
(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
(3)数据格式比较轻量,性能开销小,通信高效。
(4)可以发送文本,也可以发送二进制数据。
(5)没有同源限制,客户端可以与任意服务器通信。
(6)协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。
缺点:不兼容低版本浏览器

基本使用
浏览器提供了原生类websocket,是通过new来创建的;
websocket = new WebSocket(url, protocols)
接收两个参数:
url 表示需要连接的地址,比如:ws://localhost:8080;
protocols 可选参数,可以是一个字符串或者一个数组,用来表示子协议,这样做可以让一个服务器实现多种 WebSocket 子协议;
实例化对象提供两个方法:
send 接收一个 String|ArrayBuffer|Blob 数据,作为数据发送到服务端;
close 接收一个(可选)的 code(关闭状态号,默认为 1000) 与一个(可选)的字符串(表示断开原因),客户端主动断开连接;

连接状态:
WebSocket 类提供了一些常量表示连接状态:
WebSocket.CONNECTING 0 连接还没开启;
WebSocket.OPEN 1 连接已开启并准备好进行通信;
WebSocket.CLOSING 3 连接正在关闭的过程中;
WebSocket.CLOSED 4 连接已经关闭,或者连接无法建立;
WebSocket 的实例对象中提供了 readyState 属性来判断当前状态;

实例化对象中可以监听到以下事件:
open 连接打开的回调事件,这时 readyState 变为 OPEN;
message 收到消息的回调事件,同时回调函数接收到一个 MessageEvent 数据;
close 连接关闭的回调事件,这时 readyState 变为 CLOSED;
error 建立与连接过程发生错误的回调事件;

事件与数据
对 WebSocket 实例监听事件有两种方式,这里以 message 事件为例:
对 onmessage 属性直接赋值,正如以上:ws.onmessage = function () {};
使用 addEventListener 监听事件,如:ws.addEventListener(‘message’, function () {});
在 message 回调函数中得到 MessageEvent 类型参数 e ,我们需要的数据可以通过 e.data 获取;
需要注意的一点是:不论服务端与客户端,其接受到的数据都是序列化后的字符串(当然也有 ArrayBuffer|Blob 类型数据),很多时候我们需要解析处理数据,比如 JSON.parse(e.data);

连接稳定性
由于网络环境复杂,某些情况会出现断开连接或者连接出错,需要我们在 close 或者 error 事件中监听非正常断开并重连;
由于一些原因在 error 时浏览器并不会响应回调事件,因此稳妥的做法还需要在 open 之后开启一个定时任务去判断当前的连接状态 readyState ,在出现异常情况下尝试重连;