I am new to nodejs and socket. What I would like to know is how I should able to access my io variable in different controllers or files. Is it safe to declare my io variable as:
global.io = require('socket.io').listen(server);
so now my io is accessible in any of my controller?
I got this idea from this link:
https://blog.sylo.space/use-global-variable-for-socket-io/
It can cause crashes if it overlaps with another variable, which could be hard to track/handle if your project is quite big and/or includes a lot of librariers, it also exists for the lifetime of the application thus taking up resources. And it is overall considered bad practice to use global variables.
You can check out a great article about global variables in node.js here - http://stackabuse.com/using-global-variables-in-node-js/
EDIT: Since you mentioned safety, it is safe on theory, just not recommended.
In most cases, global variables are an indication of poor software design. A better approach would be containing all your IO code in a distinct class/module. Here's a short code piece to illustrate what I mean:
const socketIO = require('socket.io');
class myIO {
construct(server) {
this.io = socketIO.listen(server)
}
doStuff() {
// do stuff with your io socket
}
}
module.exports = myIO;
Now you need to provide an instance of myIO to your controllers, but I'm not sure what constitutes a controller in your case. And do you need to reconnect socket each time, or reuse same socket?
Either way you might want to look into Dependency Injection pattern OR use a Singleton:
module.exports = new myIO();
in this case require("myio") would always return same socket. Or if your framework has a registry, you could use that.
Related
I was pretty shocked to find out that "require" in node creates a singleton by default. One might assume that many people have modules which they require which have state, but are created as a singleton, so break the app as soon as there are multiple concurrent users.
We have the opposite problem, requires is creating a non-singleton, and we dont know how to fix this.
Because my brain is wired as a java developer, all our node files/modules are defined thusly:
file playerService.js
const Player = require("./player")
class PlayerService {
constructor(timeout) {
// some stuff
}
updatePlayer(player) {
// logic to lookup player in local array and change it for dev version.
// test version would lookup player in DB and update it.
}
}
module.exports = PlayerService
When we want to use it, we do this:
someHandler.js
const PlayerService = require("./playerService")
const SomeService = require("./someService")
playerService = new PlayerService(3000)
// some code which gets a player
playerService.updatePlayer(somePlayer)
Although requires() creates singletons by default, in the above case, I am guessing it is not creating a singleton as each websocket message (in our case) will instantiate a new objects in every module which is called in the stack. That is a lot of overhead - to service a single message, the service might get instantiated 5 times as there are 5 different sub services/helper classes which call each other and all do a requires(), and then multiply this by the number of concurrent users and you get a lot of unnecessary object creation.
1) How do we modify the above class to work as a singleton, as services don't have state?
2) Is there any concept of a global import or creating a global object, such that we can import (aka require) and/or instantiate an object once for a particular websocket connection and/or for all connections? We have no index.js or similar. It seems crazy to have to re-require the dependent modules/files for every js file in a stack. Note, we looked at DI options, but found them too arcane to comprehend how to use them as we are not js gurus, despite years of trying.
You can simply create an instance inside the file and export it.
let playerService = new PlayerService();
module.exports = playerService;
In this case, you may want to add setters for the member variables you would take as constructor parameters to ensure encapsulation.
Also note that, creating object instances with new in javascript is cheaper than traditional OOP language because of it's prototype model (more).
So don't hesitate when you really need new instances (as seen in your code, do you really want to share the timeout constructor parameter?), since javascript objects are pretty memory efficient with prototype methods and modern engines has excellent garbage collectors to prevent memory leak.
CommonJS uses a require() statement that is synchronous but what if you have a module like so:
function asyncFunction() {
var promise = ...;
return promise;
}
module.exports = asyncFunction();
what kind of problems could arise here? are you supposed to always have synchronous code returned for the module.exports object? For example if module.exports = {} it will always be synchronous, but in the above case module.exports is a promise, which is suppose is something not considered synchronous. Is there ever a good reason to use requireJS on the server side if you need to import a module that is async by nature?
what kind of problems could arise here?
This violates CommonJS conventions and will be surprising to developers. It shows you don't distinguish between code and data. Code in node on the server can and should be loaded synchronously. Data can and should use promises, callbacks, etc.
Is there ever a good reason to use requireJS on the server side
Not that I've ever seen. Speaking personally, requireJS is terrible and if your module introduced it, there is absolutely no chance I would use it in my node project.
if you need to import a module that is async by nature?
You'll need to provide specifics. I've never seen a node module that is "async by nature", at least not by someone who understands the difference between code and data and realizes that dynamically loading remote code into a running node.js server application is something most deployments want to avoid for good reasons including reliability and security.
I'm using Redis to generate IDs for my in memory stored models. The Redis client requires a callback to the INCR command, which means the code looks like
client.incr('foo', function(err, id) {
... continue on here
});
The problem is, that I already have written the other part of the app, that expects the incr call to be synchronous and just return the ID, so that I can use it like
var id = client.incr('foo');
The reason why I got to this problem is that up until now, I was generating the IDs just in memory with a simple closure counter function, like
var counter = (function() {
var count = 0;
return function() {
return ++count;
}
})();
to simplify the testing and just general setup.
Does this mean that my app is flawed by design and I need to rewrite it to expect callback on generating IDs? Or is there any simple way to just synchronize the call?
Node.js in its essence is an async I/O library (with plugins). So, by definition, there's no synchronous I/O there and you should rewrite your app.
It is a bit of a pain, but what you have to do is wrap the logic that you had after the counter was generated into a function, and call that from the Redis callback. If you had something like this:
var id = get_synchronous_id();
processIdSomehow(id);
you'll need to do something like this.
var runIdLogic = function(id){
processIdSomehow(id);
}
client.incr('foo', function(err, id) {
runIdLogic(id);
});
You'll need the appropriate error checking, but something like that should work for you.
There are a couple of sequential programming layers for Node (such as TameJS) that might help with what you want, but those generally do recompilation or things like that: you'll have to decide how comfortable you are with that if you want to use them.
#Sergio said this briefly in his answer, but I wanted to write a little more of an expanded answer. node.js is an asynchronous design. It runs in a single thread, which means that in order to remain fast and handle many concurrent operations, all blocking calls must have a callback for their return value to run them asynchronously.
That does not mean that synchronous calls are not possible. They are, and its a concern for how you trust 3rd party plugins. If someone decides to write a call in their plugin that does block, you are at the mercy of that call, where it might even be something that is internal and not exposed in their API. Thus, it can block your entire app. Consider what might happen if Redis took a significant amount of time to return, and then multiple that by the amount of clients that could potentially be accessing that same routine. The entire logic has been serialized and they all wait.
In answer to your last question, you should not work towards accommodating a blocking approach. It may seems like a simple solution now, but its counter-intuitive to the benefits of node.js in the first place. If you are only more comfortable in a synchronous design workflow, you may want to consider another framework that is designed that way (with threads). If you want to stick with node.js, rewrite your existing logic to conform to a callback style. From the code examples I have seen, it tends to look like a nested set of functions, as callback uses callback, etc, until it can return from that recursive stack.
The application state in node.js is normally passed around as an object. What I would do is closer to:
var state = {}
client.incr('foo', function(err, id) {
state.id = id;
doSomethingWithId(state.id);
});
function doSomethingWithId(id) {
// reuse state if necessary
}
It's just a different way of doing things.
For some user requests, I need to do some heavy computations (taking about 100ms of time); and, of course, I do not want to perform these in node's main event loop so that it will prevent other requests from serving.
The most obvious, but definitely not the cleanest way to solve this problem would be to offload the computations to another program and wait for the results asynchronously.
Is there any way to do it without leaving the node process (and implementing inter-process communications)? E.g. something like this:
var compute = function (input) {
var i,
result = input;
for (i = 0; i < 1000000; i++) {
result = md5(result);
}
}
var controller = function (req, res) {
offload(compute, req.params.input, function(result) {
res.send(result);
});
}
I found a compute-cluster module, which seems to be designed exactly for my goals. It spawns children processes, and the communication is made with IPC (no sockets wasted).
The JavaScript language has no support for threads and node.js provides no interface to them either so you'll need to rely on a library to provide threading functionality. See the node-fibers and node-threads-a-go-go libraries for possible solutions.
If you're looking for a way to make IPC a little easier in node.js then consider using the zeromq library (node.js bindings). This somewhat-related-answer might be useful as well.
I was wondering if using require() in node.js was the equivalent to lazy loading?
For example if I had a function that required a specific node.js package that wasn't needed anywhere else in my code am I best to use require() inside of that function to include the needed package only when that function is called.
I'm also unsure if this will provide any performance improvements given my lack of understanding around the node.js architecture? I presume it will use less memory per connection to my server. However will it increase I/O to the disk when it has to read the package, or will this be a one off to get it in memory?
If this is the case how far should I take this, should I be trying to write node.js packages for as much code as I can?
require() is on-demand loading. Once a module has been loaded it won't be reloaded if the require() call is run again. By putting it inside a function instead of your top level module code, you can delay its loading or potentially avoid it if you never actually invoke that function. However, require() is synchronous and loads the module from disk so best practice is to load any modules you need at application start before your application starts serving requests which then ensures that only asynchronous IO happens while your application is operational.
Node is single threaded so the memory footprint of loading a module is not per-connection, it's per-process. Loading a module is a one-off to get it into memory.
Just stick with the convention here and require the modules you need at the top level scope of your app before you start processing requests. I think this is a case of, if you have to ask whether you need to write your code in an unusual way, you don't need to write your code in an unusual way.
If you want to lazy load modules, its now possible with ES6 (Node v6)
Edit: This will not work if you need to access properties of require (like
require.cache).
module.js
console.log('Module was loaded')
exports.d=3
main.js
var _require = require;
var require = function (moduleName) {
var module;
return new Proxy(function () {
if (!module) {
module = _require(moduleName)
}
return module.apply(this, arguments)
}, {
get: function (target, name) {
if (!module) {
module = _require(moduleName)
}
return module[name];
}
})
};
console.log('Before require');
var a = require('./module')
console.log('After require');
console.log(a.d)
console.log('After log module');
output
Before require
After require
Module was loaded
3
After log module