我在CoffeeScript / NodeJS中看到一些关于EventEmitters和处理程序的非常奇怪的行为。我把一个展示问题的小样本放在一起......
基本上我在事件处理中有一些间接,但我似乎无法让它工作,除非我将第一个事件处理程序包装在lambda中,并且我想了解为什么/如果有什么我可以做的事情做这个工作。从我的思维方式来看,基本上test1()
应该与test3()
具有相同的行为。包含test2()
只是为了表明第二级事件处理有效!
events = require "events"
class ExampleEmitter extends events.EventEmitter
constructor: () ->
go1: () ->
console.log("fire 1")
@emit("test1", "there")
go2: () ->
console.log("fire 2")
@emit("test2", "there")
class ExampleHandler
constructor: () ->
handle: (x) -> console.log("hey", x)
test1 = () ->
handler = new ExampleHandler()
emitter1 = new ExampleEmitter()
emitter2 = new ExampleEmitter()
emitter1.on "test1", emitter2.go2
emitter2.on "test2", handler.handle #this doesn't fire :(
emitter1.go1()
test2 = () ->
handler = new ExampleHandler()
emitter1 = new ExampleEmitter()
emitter2 = new ExampleEmitter()
emitter1.on "test1", emitter2.go2
emitter2.on "test2", handler.handle
emitter2.go2()
test3 = () ->
handler = new ExampleHandler()
emitter1 = new ExampleEmitter()
emitter2 = new ExampleEmitter()
emitter1.on "test1", () -> emitter2.go2() #why must I wrap this?
emitter2.on "test2", handler.handle
emitter1.go1()
console.log "\ntest1"
test1()
console.log "\ntest2"
test2()
console.log "\ntest3"
test3()
这是输出:
test1
fire 1
fire 2
test2
fire 2
hey there
test3
fire 1
fire 2
hey there
答案 0 :(得分:5)
emitter1.on "test1", () -> emitter2.go2() #why must I wrap this?
因为如果你只是传递emitter2.go2
,go2将在根对象(浏览器中为window
;我不太了解node.js)的上下文中调用,而不是emitter2
。一个函数本身并不知道它所属的对象。实际上,您应该将关闭传递给on
的两个调用。
为了使事情看起来更好一点,如果你的闭包不带任何参数,你可以省略括号。最终,你应该有这样的东西:
handler = new ExampleHandler()
emitter1 = new ExampleEmitter()
emitter2 = new ExampleEmitter()
emitter1.on "test1", -> emitter2.go2()
emitter2.on "test2", -> handler.handle()
emitter1.go1()
如果你仍然不喜欢它的外观,那么下一个最好的方法是使用一个函数,通过创建这样的闭包将函数“绑定”到对象。但是,它不会为你节省任何打字,我觉得它看起来很丑陋而且难以理解:
bindMethod = (obj, funcName) ->
-> obj[funcName].apply(obj, arguments)
...
emitter1.on "test1", bindMethod(emitter2, 'go2')
emitter2.on "test2", bindMethod(handler, 'handle')
最后,您可以使用胖箭头=>
在类声明中创建此类绑定方法,以便您可以根据需要传递它们。 go2: -> ...
将成为go2: => ...
,& c。但在这种情况下,我认为这是一种奇怪的行为。我坚持传递闭包,因为它使意义更清晰。
答案 1 :(得分:1)
我会在这里添加另一个答案,即使我已经接受了上面的答案,以防人们不阅读评论......
我的问题的实际修复,是为了获得我正在寻找的行为,是在我的课程定义中使用=>
'胖箭',而不是普通的->
'细箭头'像我一样,将函数绑定到类的实例。所以:
class ExampleEmitter extends events.EventEmitter
constructor: () ->
go1: () =>
console.log("fire 1")
@emit("test1", "there")
go2: () =>
console.log("fire 2")
@emit("test2", "there")