当前位置: 首页 > Web前端 > HTML5

WebWorker和WebSocket实现了前端消息总线

时间:2023-04-05 23:46:32 HTML5

WebWorker使得JS具备多线程能力,可以将复杂耗时的操作交给Worker线程处理。WebSocket允许Web端与服务器端保持有效的长连接,使服务器端能够主动推送数据。两者结合,可以将业务系统的信息流通知功能完全剥离出来。架构图JSWorkerWorker在专用范围DedicatedWorkerGlobalScope中工作。在此范围内,不能直接操作DOM节点,不能使用Window对象的默认方法和属性。但是,访问网络是完全没有问题的。请点击这里查看具体可以使用的对象和方法。从上图可以清楚的看出,Worker实现了当前架构中一个bridge的左右两边。这里先了解下Worker本身的功能实现。主线程和Worker线程通过postMessage方法相互传递信息。主线程和Worker线程通过onmessage事件接收相互传递的消息。Worker中引入一个第三方js。使用方法importScripts([url,])主线程调用worker.terminate()结束线程Worker线程通过调用this.close()结束自己的线程创建一个新的webworker.js文件,写入如下代码在里面//author:herbertqq:464884492onmessage=function(event){if(event.data.code){varcode=event.data.code.toLowerCase();开关(代码){case"init":varuserId=event.data.loggedUserId;varsessionId=event.data.sessionid;如果(!sessionId){this.close();返回;}postMessage({code:"codeone",msg:"Hello,component1"});postMessage({code:"codetwo",msg:"Hello,component2"});休息;默认值:中断;}}}注意:onmessage前不要加var,否则IE下收不到消息。IE真是一个令人沮丧的浏览器。新建一个index.html页面,在脚本块中写入如下代码与webworker.js通信//author:herbertqq:464884492varwork=newWorker('webworker.js'),textone=document.querySelector("#textone"),textTwo=document.querySelector("#texttwo")textAll=document.querySelector("#textAll");work.onmessage=function(event){vardata=event.数据;if(!!data.code){switch(data.code){case"close":work.terminate();case"codeone":textone.value=textone.value+JSON.stringify(data)+"\r\n";textAll.value=textAll.value+JSON.stringify(data)+"\r\n";休息;case"codetwo":textTwo.value=textTwo.value+JSON.stringify(data)+"\r\n";textAll.value=textAll.value+JSON.stringify(data)+"\r\n";休息;默认值:textAll.value=textAll.value+JSON.stringify(data)+"\r\n";}}};work.postMessage({code:"init",loggedUserId:'demo',sessionid:'demo'});JSWebSocketWebSocket和Http都是基于Tcp协议的。不同的是,WebSocket实现了服务端和客户端的全连接双工通信。在Websocket出现之前,如果要实现一个信息推送的功能,通过http实现的唯一方案就是轮训。现在有了WebSocket,一切都好办了。接下来,我们开始创建WebSocket连接。方法中的root代表当前作用域,主线程中root=window,WebWorker线程中root=DedicatedWorkerGlobalScope//author:herbertqq:464884492varroot=this,socket=null;functionconnect(wsurl){if('WebSocket'inroot){socket=newWebSocket(wsurl);}elseif('MozWebSocket'inroot){socket=newMozWebSocket(wsurl);}else{alert("您的浏览器版本太低,您将无法接收系统消息");wsurl格式为ws:\\或wss:\\,后者表示SSL加密传输。实际地址如下:ws://localhost:8090/demo/demowebsocket接下来我们需要为socket处理事件,负责接收服务器推送的消息//author:herbertqq:464884492functiononOpen(){postMessage({代码:"openConnect"});}functiononClose(){postMessage({code:"closewsconnect"});}functiononMessaage(event){postMessage(JSON.parse(event.data));}functiononError(event){socket=null;if(event.target.readyState==3){//断线重连setTimeout(function(){connect(event.target.url);initMessageEvent();},1000);}}functionsendMessage(msg){if(socket==null)返回;套接字发送(消息);}functioninitMessageEvent(){socket.onopen=onOpen;//socket连接成功处理事件socket.onclose=onClose;//socket连接关闭处理Eventsocket.onmessage=onMessaage;//socket收到一条新消息socket.onerror=onError;//socket错误处理事件}JAVAWebSocketTomcat7x已经实现了标准我们bScoket接口,只需要在项目中写一个普通的entitybean配置注解即可实现一个标准的WebSocketApi在开发中,一些注解@ServerEndpoint主要用于设置WebSocket连接地址,url参数如:@ServerEndpoint(value="/demowebsocket/{userId}/{sessionId}"),其中{userId}和{sessionId}都是pathParams,可以用在onOpen函数中,通过函数参数获取@PathParam@PathParam获取URL地址上对应的注解参数@OnOpen建立连接注解@OnClose关闭连接注解@OnMessage接收消息注解@OnError错误注解Functions受注解约束可以任意选择需要的参数。可选参数有Session、EndpointConfig和@PathParam,服务端Bean代码如下//author:herbertqq:464884492@ServerEndpoint(value="/demowebsocket/{userId}/{sessionId}")staticfinalSetconnections=newCopyOnWriteArraySet();私人会议;publicDemoWebSokcet(){}@OnOpenpublicvoidopenConnection(Sessionsession,EndpointConfigconf,@PathParam("userId")StringuserId,@PathParam("sessionId")StringsessionId){this.session=session;connections.add(这个);JSONObjectjo=newJSONObject();jo.put("code","newuser");jo.put("userid",userId);jo.put("sessionid",sessionId);jo.put("msg","server:newconnectionuser");发送消息(乔);//测试代码JSONObjectjo1=newJSONObject();jo1.put("code","codeone");jo1.put("userid",userId);jo1.put("sessionid",sessionId);jo1.put("msg","Server:Hellocomponent1");发送消息(jo1);JSONObjectjo2=newJSONObject();jo2.put("code","codetwo");jo2.put("userid",userId);jo2.put("sessionid",sessionId);jo2.put("msg","server:hellocomponent2");发送消息(jo2);}@OnClosepublicvoidcloseConnection(@PathParam("userId")StringuserId,@PathParam("sessionId")StringsessionId){connections.remove(this);JSONObjectjo=newJSONObject();jo.put("code","connectionClose");jo.put("userid",userId);jo.put("sessionid",sessionId);jo.put("msg","server:connectionclosed");发送消息(jo);}//处理短信@OnMessagepublicvoidhandleTextMsg(Sessionsession,Stringmessage,@PathParam("userId")StringuserId,@PathParam("sessionId")StringsessionId){System.out.println("userId=>"+userId+"sessionId=>"+sessionId);//按原样转发客户端消息sendMessage(JSONObject.parseObject(message));}//处理二进制消息@OnMessagepublicvoidhandleBinaryMsg(Sessionsession,ByteBuffermsg,@PathParam("userId")StringuserId,@PathParam("sessionId")StringsessionId){}//处理pong消息@OnMessagepublicvoidhandlePongMsg(Sessionsession,PongMessagemsg,@PathParam("userId")StringuserId,@PathParam("sessionId")StringsessionId){JSONObjectjo=newJSONObject();jo.put("code","pong");jo.put("userid",userId);jo.put("sessionid",sessionId);jo.put("msg",msg.getApplicationData().toString());发送消息(乔);}@OnErrorpublicvoidonError(Throwablet,@PathParam("userId")StringuserId,@PathParam("sessionId")StringsessionId)throwsThrowable{JSONObjectjo=newJSONObject();jo.put("code","servererror");jo.put("userid",userId);jo.put("sessionid",userId);jo.put("msg",t.getMessage());发送消息(乔);}privatestaticvoidsendMessage(JSONObjectmsg){for(DemoWebSokcetclient:connections){try{synchronized(client){client.session.getBasicRemote().sendText(msg.toJSONString());}}catch(IOExceptione){JSONObjectjo=newJSONObject();jo.put("code","servererror");jo.put("userid",client.session.getPathParameters().get("userid"));jo.put("sessionid",client.session.getPathParameters().get("sessionid"));connections.remove(客户端);试试{client.session.close();}catch(IOExceptione1){}jo.put("msg","server:发送消息异常,连接已关闭"+e.getMessage());发送消息(乔);}}}}在写测试代码的过程中,通过pom引入了javax.websocket-api,启动后一直出现ErrorDuringWebSockethandshake:Unexpectedresponsecode:404connectionerror,然后直接拷贝tomcat下实现的jartomcat/bin到webapp对应的bin文件夹即可解决问题。演示预览摘要很长,在这里阅读起来并不容易!把WebWorker和WebSocket结合起来对我来说也是第一次。感觉现在javascript函数真的是越来越丰富了。demo地址,一点点感悟,对于开发中的新知识点,首先要学会使用,其次通过阅读源码和理论知识,才能更顺手使用,甚至改它。

最新推荐
猜你喜欢