Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

node, require, singleton or not singleton?

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.

like image 382
John Little Avatar asked Nov 04 '25 00:11

John Little


1 Answers

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.

like image 75
shawon191 Avatar answered Nov 05 '25 15:11

shawon191



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!