1

I'm trying to find the right strategy to access a existing object from within my events handler, and wonder if the bypass I propose here after is a good option or not.

In following sample, I have a class to built a simple TCPServer. After server creation time, when a new tcpclient arrives, within "ConnectAction" function I need to access "devName" variable to find which server instance is concerned. As a result "DevName" cannot be global and needs to be specific to current instantiation of my TCPServer object.

  ------ Extract from my code --------
  // TCPserver Object Class
  TcpServer = function (devName, port) {

  // event handler executed each time a new TCP client connect to the server
  ConnectAction = function (socket) {      
      // for ech new client we create a new device and store it within server object
      device = new TCPClient (devName, socket);
  };

  this.server = net.createServer(ConnectAction);
  this.server.listen(port);
  return this;
  }
  Server1 = new TcpServer ("My First Server", 8080):
  Server2 = new TcpServer ("My Second Server", 8081):

In other script languages that I used in the past, it was possible to add an extra argument to event handlers. But in NODE.JS something like server=net.createServer(ConnectAction SomeExtraHandler); does not work.

The only bypass I find is to leverage arguments passed at object construction time. When the event handler code is embedded within the object border as in this example; then while even handlers are called outside of TCPserver object context "this not defined", handlers can still leverage parameters that where passed at object creation time. In this case "devName".

My question: is my bypass safe ? is there a better approach to solve this issue ? The full code of my sample is available at: http://www.fridu.org/download/private/TcpServer.js

If anyone has a better strategy, I would be more than happy to learn about it. In my real application, I should have ten or so differences server instances, with few hundred of clients connected to each of them. Which raise a second question, will my object coding approach in node.js support the load ?

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Fulup
  • 545
  • 3
  • 14
  • Why can't you just use `devName` inside `ConnectAction`? The `ConnectAction` function has access to the parent scope which contains `devName`. Also, `return this` is unnecessary. – mscdex Aug 28 '14 at 14:27
  • If you have multiple instance of TcpServer having access to parent scope is not enough. – Fulup Aug 28 '14 at 15:54

2 Answers2

1

My question: is my bypass safe?

Yes, it's totally safe. Using closures is the javascript way to solve this problem, you don't need to explicitly pass extra arguments around.

Notice however that ConnectAction, ListenAction and device should not be global variables, they are instance-specific and would better be scoped to the constructor as well; else they might interfere with other tcp servers.

is there a better approach to solve this issue?

There is a different, although not necessarily better, way: put the devName as a property on your object. The connectAction is called within the context of your server, so you can simply access it there - at least that would be the case if your TcpServer would inherit from the net.Server. As you have a wrapper around your server, you could do something like this:

// event handler executed each time a new TCP client connect to the server
function ConnectAction(socket) {      
    // for ech new client we create a new device and store it within tcp server object
    this.tcp.device = new TCPClient (this.tco.devName, socket);
}
function TcpServer(devName, port) {
    this.devName = devName;
    this.server = net.createServer(ConnectAction);
    this.server.tcp = this;
    this.server.listen(port);
}
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Bergi: Very good, I though event handler where outside of any object context, but the fact they are attache to server context is a very good news. I tested your proposal, it works great. Thank you – Fulup Aug 28 '14 at 16:04
0

It should be perfectly fine to use devName as you are already doing. However, if you want or need to move your ConnectAction function outside your TcpServer implementation for some reason, you could use bind() to accomplish what you're trying to do.

Relevant bit from the docs:

bind() also accepts leading default arguments to provide to the target function when the bound function is called.

What this means in your case is that you can create a bound version of ConnectAction which already has devName set as one of its arguments. It would look something like this:

ConnectAction = function (devName, socket) {      
    // for ech new client we create a new device and store it within server object
    device = new TCPClient (devName, socket);
};

var boundConnectAction = ConnectAction.bind(undefined, devName)
this.server = net.createServer(boundConnectAction);

In that code, boundConnectAction will still be called from createServer as normal (boundConnectAction(socket)) but, because it's bound to ConnectAction with a default argument for devName, it will pass on that call as if it was ConnectAction(devName, socket).

Note: bind()'s first argument is used as this in the bound function. Since ConnectAction doesn't look like its intended to be an object/class instance method, I just passed undefined, but you might want to pass something else depending on your use case.


As to your other question regarding node handling the load, I'd suggest splitting out your ten or so server instances in to separate node processes so that the load is better distributed. Take a look at child_process or possibly cluster to help out with that.

Mike S
  • 41,895
  • 11
  • 89
  • 84
  • Mike: This is exactly what I was looking for. I tested your proposal, and I confirm that it works great. This being said the solution propose just after by Bergi look cleaner from a object approach point of view. Thank you. – Fulup Aug 28 '14 at 16:15