我正在写一个单页的ws-++网站,我想让我的代码先按"page"分组(我想我需要一个新词,因为它永远不会回发),然后按节分组,然后按概念分组。
我想在我的代码中拆分WebSocket.onmessage
,就像$('#someElement')
可以不断地添加click(function(){})
这样的事件一样
这可以用WebSocket.onmessage(function(){})
完成吗?如果是,如何?
正如一些jQuery程序员很高兴地知道的那样,一个事件最初可以设置,然后在js的多个位置添加。这是我最喜欢js的地方,"只要它有序,就把它放在任何地方"的能力。这至少让代码组织对我来说容易多了。
对于WebSockets,实际上,到目前为止,我的操作客户端是使用WebSocket.onmessage()
处理程序,因为WebSocket.send()
可以在任何地方使用,实际上只是将js数据端口到服务器。
onmessage()
现在拥有我的页面,因为其中的任何内容都会启动大多数主要操作,例如在收到"登录成功"类型的消息后,将登录屏幕淡出到第一个内容屏幕。
根据我对js的有限理解,onmessage()
处理程序必须全部设置在一个地方。在我更改了它周围的js之后,继续向后滚动/切换到另一个文件来对它进行更改是一件很痛苦的事情。
如何在js的多个位置添加到WebSocket.onmessage()
处理程序?
回答您的最后一个问题;
如何在js的多个位置添加onmessage处理程序?
您可以定义自己的个人(全局)事件处理程序,在其中您可以接受任意数量的处理程序函数。这里有一个例子:
window.bind: function(name, func, context) {
if (typeof this.eventHandlers[name] == "undefined") {
this.eventHandlers[name] = [func];
this.eventContexts[name] = [context];
}
else {
var found = false;
for (var index in this.eventHandlers[name]) {
if (this.eventHandlers[name][index] == func && this.eventContexts[name][index] == context) {
found = true;
break;
}
}
if (!found) {
this.eventHandlers[name].push(func);
this.eventContexts[name].push(context);
}
}
}
window.trigger: function(name, args) {
if (typeof this.eventHandlers[name] != "undefined") {
for (var index in this.eventHandlers[name]) {
var obj = this.eventContexts[name][index];
this.eventHandlers[name][index].apply(obj, [args]);
}
}
}
// === Usage ===
//First you will bind an event handler some where in your code (it could be anywhere since `.bind` method is global).
window.bind("on new email", function(params) { ... });
//Then you need to trigger "on new email" in `onmessage` once appropriate events happen.
WebSocket.onmessage(function(data) {
//Work on data and trigger based on that
window.trigger("on new email", { subject: data.subject, email: data.email });
})
这段代码是我以前参与的一个开源项目的一部分。它提供事件名称,并允许您为处理程序设置上下文(用于方法而非函数)。然后,您可以在套接字的onmessage处理程序中调用触发器。我希望这就是你想要的。
您可以创建一个包装器,该包装器将处理自身上的WS事件。参见此示例CoffeeScript:
class WebSocketConnection
constructor: (@url) ->
@ws = new WebSocket(@url)
@ws.onmessage = @onMessage
@callbacks = []
addCallback: (callback) ->
@callbacks.push callback
onMessage: (event) =>
for callback in @callbacks
callback.call @, event
# and now use it
conn = new WebSocketConnection(url)
conn.addCallback (event) =>
console.log event
您可以使用addEventListener
:
socket.addEventListener('message', function (event) {
console.log('Message from server ', event.data);
});
我构建了一个CoffeeScript类来解决这个问题。它与@Valent的类似,但功能更全面,所以我想我会分享它。它为web套接字事件提供"on"
、"off"
和"clear"
方法,还为"send"
和"close"
提供转发功能,这样你几乎不必直接触摸套接字。如果您确实需要访问实际的WebSocket对象,您可以通过superWebSocket.ws
访问。
edit:我添加了一个getConnection
静态方法来生成依赖url的singleton。这样,每个url只有一个连接,如果你试图创建第二个连接,它只会给你现有的连接。它还可以防止任何人直接调用构造函数。
edit:我使用JSON通过套接字进行通信。我添加了一些代码,这些代码将对传递到send
的任何非字符串运行JSON.stringify
,还将尝试对通过处理程序接收的任何消息运行JSON.parse
。
superSockets = {}
class SuperWebSocket
@getConnection: (url)->
superSockets[url] ?= new SuperWebSocket url
superSockets[url]
constructor: (url)->
if arguments.callee.caller != SuperWebSocket.getConnection
throw new Error "Calling the SuperWebSocket constructor directly is not allowed. Use SuperWebSocket.getConnection(url)"
@ws = new WebSocket url
events = ['open', 'close', 'message', 'error']
@handlers = {}
events.forEach (event)=>
@handlers[event] = []
@ws["on#{event}"] = (message)=>
if message?
try
message = JSON.parse message.data
catch error
for handler in @handlers[event]
handler message
null
on: (event, handler)=>
@handlers[event] ?= []
@handlers[event].push handler
this
off: (event, handler)=>
handlerIndex = @handlers[event].indexOf handler
if handlerIndex != -1
@handlers[event].splice handlerIndex, 1
this
clear: (event)=>
@handlers[event] = []
this
send: (message)=>
if typeof(message) != 'string'
message = JSON.stringify message
@ws.send message
close: => @ws.close()