阅读 779

websocket 运用详解

一、简介:

websocket 建立网络长链接,最开始存在的意义就是为了解决我们使用 '轮询' 的方式进行网络请求,轮询的效率很低并且浪费网络资源,一般使用定时器来实现,而 websocket 的出现就解决了这个问题。它实现了服务器端直接向客户端推送消息,并且客户端也可以直接向服务端发送消息,这是一个真正的双向平等对话。最典型的例子就是聊天室。

二、客户端的简单实现方法:

1.实例化一个 ws 对象 ,即:

var ws = new WebSocket(' url ');
复制代码

2.简单的步骤:

①链接打开的事件监听:
ws.onopen = function(event) {   
    console.log("Connection open ..."); 
    ws.send("Hello WebSockets!");   // 向服务器发送数据
};
复制代码
②监听消息事件,当有消息到达就会直接触发:
ws.onmessage = function(event) {
    console.log( "Received Message: " + evt.data);
    ws.close();   // 关闭请求
};
复制代码
③监听关闭事件,当使用close 时触发:
ws.onclose = function(event) {
    console.log("Connection closed.");
};
复制代码
④错误监听:
ws.onerror = function( err ){
    console.error(err)
}
复制代码

此处注意事项:

使用 onmessage 接受消息的时候,我们可以指定数据类型,服务器的数据可能是文本,也可能是二进制数据, 以上就是一个最基本的客户端的 websocket 实现;

三、WebSocket.readyState 实例对象的当前状态:

通过 switch 可以直接查看;

switch (ws.readyState){
    case WebSocket.CONNECTING:
        console.log('值为0,表示正在创建链接');
        break;
    case WebSocket.OPEN:
        console.log('值为1,表示连接成功,可以通信');
        break;
    case WebSocket.CLOSING:
        console.log('值为0,表示正在关闭链接');
        break;
    case WebSocket.CLOSED:
        console.log('值为0,表示连接已经关闭或者打开连接失败');
        break;
    default:
        break;
}
复制代码

四、日常代码开发封装:

在平时我们写代码的时候,可以通过封装一个类来实现 socket 长链接,具体代码如下:

class SocketManager {
    _socketMsgQueue = [];
	_isOpen = false;
	_messageCbs = [];

	constructor(url) {
	    if(!url) {
    		console.error('SocketManager: url is required');
    		return;
            }
		this._url = url;
		this._init();
        // 判断是否有url  的存在,如果没有就return,否则执行init () 方法;
	}

    _init() {
        // 创建WebSocket 链接:
        this._socketInstance = new WebSocket(this._url);
        // 打开链接并发送数据:
        this._socketInstance.onopen = () => {
            this._isOpen = true;
	    for (let i = 0; i < this._socketMsgQueue.length; i += 1) {
                    this.sendMessage(this._socketMsgQueue[i]);
            }
       		this._socketMsgQueue.length = 0;
       	};

		 this._socketInstance.onmessage = (e) => {
   		    for (let i = 0; i < this._messageCbs.length; i += 1) {
       		    this._messageCbs[i](e.data);
   			}
	 	};

 	    this._socketInstance.onclose = () => {
           	 this.destroy();
           	 this._init();
        };
    }
    //调用的回调,这个地方比较绕,我想了大半天!!!和上述的onmessage 时间相对应			
    的。我们调用的时候,将一个函数出入,所以此时数组中保存的多个函数!!!所以在
    onmessage 中,我们拿到的e.data 就是数据使用for 循环,调用每一个函数!!! 
   	registerMessage(cb) {
        if (typeof cb === 'function') {
            this._messageCbs.push(cb);
        }
    }
    // 发送数据,可通过this._isOpen 来判断是否打开了长链接;
    sendMessage(msg) {
        if (this._isOpen) {
            this._socketInstance.send(msg);
        } else {
            this._socketMsgQueue.push(msg);
        }
    }
    // 销毁此次长链接
    destroy() {
        this._socketInstance.close();
        this._socketInstance.onmessage = null;
        this._socketInstance.onopen = null;
        this._socketInstance.onclose = null;
        
        delete this._socketInstance;
    }
}

export default SocketManager;
复制代码

五、封装对象的调用:

1.首先引入我们封装对象的文件;import ....

2.由于我们封装的时候是将这个对象暴露出去的,所以在引入之后,直接new 这个对象即可:

    const socketMng = new SocketManager(xcxSocketUrl);
复制代码

注意:这个地方的 url 是必须传入的,在对象中也做了一个判断!

3.执行方法:

socketMng.sendMessage('这是数据!!!');
socketMng.registerMessage((msg)=>{
    if(...){
        // 执行相应的操作!
    }
})
复制代码

注意:此时的这个箭头函数,就是我们在registerMessage ()中传入的值,即cb;

以上就是最近写 WebSocket 所学习到的所有知识了,希望对大家有所帮助!!!不喜勿碰....