0

I'm currently playing around with coffeescript and websockets using nodejs.
I created a class SocketHandler for managing websocket clients:

class SocketHandler
    constructor: (@server) ->
        @server.on "connection", @onClientConnect   

    onClientConnect: (socket) ->
        console.log "client connected"
        socket.on "close", @onClientDisconnect

    onClientDisconnect: (code, message) ->
        console.log "client disconnected"

ws = require "ws"
server = ws.Server { port: 8080 }
sockethandler = new SocketHandler server

When I run the script and a client connects I get the following error message:

client connected
events.js:210
    throw new TypeError('listener must be a function');
    ^

TypeError: listener must be a function
[...]

I have no clue why this happens. In my view I'm passing a function reference to socket.on as the second parameter.

I tried to investigate further and tried to output onClientDisconnect to see what type it has.
So I changed

onClientConnect: (socket) ->
    console.log "client connected"
    socket.on "close", @onClientDisconnect

to

onClientConnect: (socket) ->
    console.log "client connected"
    console.log @onClientDisconnect
    socket.on "close", @onClientDisconnect

resulting in getting an undefined value as output.

Now I'm really confused and I think I'm missing something fundamental at how the language works.
Can anyone of you help me out?

TorbenJ
  • 4,462
  • 11
  • 47
  • 84

1 Answers1

1

Reminder: @onClientConnect is shorthand for this.onClientConnect. this is exactly the problem here. The context of a function call (what this is inside a function) is determined at call time in Javascript. When you pass a function, the receiver receives it "without context", and when invoked as such, this won't refer to the this you're thinking/want/expect.

Long story short: you need to bind this to your function, so the @ in @onClientDisconnect actually refers to your class instance:

@server.on "connection", @onClientConnect.bind @

Alternative in CoffeeScript (using a context-bound fat arrow callback):

@server.on "connection", => @onClientConnect()

Also see How to access the correct `this` context inside a callback?

Community
  • 1
  • 1
deceze
  • 510,633
  • 85
  • 743
  • 889