NodeJS module with parameters - node.js

I want to create a module with socket.io parameter so I would have a globally set variable in my module class.
My question is how would one do it and still access the functions in that model class?
in term I would want something like what you can do with socket.io lib,
this is how you define the socket.io lib in the main app class and you can see that you need to pass a server parameter and you can use the objects funnctions.
const io = require('socket.io')(server);
Also this is the exact object I want to pass to my model.

Model file:
var storedObject
module.exports = (myObject) => {
if(myObject){
// set object only if provided
// this way you will be able to init once and use everywhere this model
storedObject = myObject
}
return {
getA: getA
}
}
function getA(){
return storedObject.a
}
Usage example:
var obj = {a: 1, b: 2} // can also be a socket.io or any other object
var model= require('./model.js')(obj) // call with object only on initialization
console.log(model.getA())

Related

How node-modules are implemented in node.js , how function implemention and creating instance are same in socket.io

const io = require('socket.io')();
// or
const Server = require('socket.io');
const io = new Server();
I am confused with following syntax
1) what is socket.io (is it a class or interface i checked the documention in node.js it showed be interface )
2)If it is interface i think we have to use class for using it (i didn't see any documentation to implement interface in javascript )
3) for understanding i tried the following (created 2 files)
example.js
module.exports = function () {
console.log("welcome to javascript");
}
use.js
let imp = require('./example')()
From following Link i have learned about require [https://nodejs.org/en/knowledge/getting-started/what-is-require/][1]
Now i am confused how socket is implemented and how the following 2 syntax's are equal
If socket is a function we can call by
const io = require('socket.io')();
If it is a class we generally do the following (create a instance and use it )
const Server = require('socket.io');
const io = new Server();
But in the documention they said both the syntax are equal how ?
One is for excuting the module.exports and one is used for instancing a class how both are equal
When you do this:
let x = require('someModule');
The value of x is whatever the module sets the module.exports value to in the module. It can literally be anything. It's entirely up to the module what they assign to that. It is often an object (with properties), but it can also be a function and sometimes it's even a function with properties.
To see what socket.io assigns to module.exports, we can go right to the source where we see:
module.exports = Server;
So, then we go look at what is Server and find this:
function Server(srv, opts){
if (!(this instanceof Server)) return new Server(srv, opts);
if ('object' == typeof srv && srv instanceof Object && !srv.listen) {
opts = srv;
srv = null;
}
opts = opts || {};
this.nsps = {};
this.parentNsps = new Map();
this.path(opts.path || '/socket.io');
this.serveClient(false !== opts.serveClient);
this.parser = opts.parser || parser;
this.encoder = new this.parser.Encoder();
this.adapter(opts.adapter || Adapter);
this.origins(opts.origins || '*:*');
this.sockets = this.of('/');
if (srv) this.attach(srv, opts);
}
From that, we can see that it is a constructor function that can be called as either:
const x = new Server(...);
or as:
const x = Server(...);
So, the answer is as follows:
require('socket.io') gives you a constructor function.
That constructor function can be caller either with new or just as a regular function and it adapts to return the same thing, a new server object.
So, when you do this:
const server = require('socket.io')();
it first gets the exported constructor function and then calls it and assigns the newly created object to the server variable.
1) what is socket.io (is it a class or interface i checked the documentation in node.js it should be interface )
socket.io on the server exports a constructor function for creating a server object. It can be called either as a regular function or with new.
2)If it is interface i think we have to use class for using it (i didn't see any documentation to implement interface in javascript )
It's a function. Javascript doesn't have a specific type called an interface. The socket.io code defines a constructor the older fashioned way (before the class keyword existed) though the outcome is largely the same. It defines a constructor function that, when called will create an object of the desired type.
3) Now i am confused how socket is implemented and how the following 2 syntax's are equal
In Javascript, these two different pieces of code create the same server object:
const io = require('socket.io');
const server = io();
and
const server = require('socket.io')();
The second is just a shortcut that doesn't assign the intermediate result from require('socket.io') to a variable, but rather just calls it directly. It will work like this only when the first function call returns a function. So, the first syntax gets a function, assigns it to the io variable and then calls it. The second syntax gets the function and immediately calls it without assigning it to a variable. In both cases the result of getting the function and calling it ends up in the server variable.

Passing a parameter trough require-module to ES6 class in Nodejs

I am learning to use ECMAScript6 -styled classes in NodeJS (7.7.3). I have used this kind of programming style:
//app.js
var forecastHandler = require('./forecastHandler.js');
//forecastHandler.js
class ForecastHandler {
constructor() {}
}
module.exports = new ForecastHandler()
It has worked well until now, because I have to pass parameters to module.
//app.js
var forecastHandler = require('./forecastHandler.js')(3600);
//forecastHandler.js
class ForecastHandler {
constructor(cacheUpdateDelay) {}
}
module.exports = new ForecastHandler(cacheUpdateDelay)
I got this error: ReferenceError: cacheUpdateDelay is not defined.
Can I pass the parameter to ForecastHandler-module using ES6 styled classes and creating an object at module.exports? If I only export the class and create the object in app.js, code works, but it's syntax is ugly.
//app.js
var forecastHandlerClass = require('./forecastHandler.js');
var forecastHandler = new forecastHandlerClass(3600);
//forecastHandler.js
module.exports = ForecastHandler
EDIT: better examples
module.exports = new ForecastHandler(cacheUpdateDelay)
The trouble with this code is that it initialises the object when the code is first run.
require('./forecastHandler.js') means "execute all the code in forecastHandler.js and give me the exports object. This means that the JS engine tries to run new ForecastHandler(cacheUpdateDelay) when there is no cacheUpdateDelay created.
The simple way to do this is the one you provide. Load the class, then try to make a new instance of it. If you really want to one-line it, you can do this in app.js:
var forecastHandler = new (require('./forecastHandler.js'))(3600);
There are various other ways you could do this. The simplest involve not exporting a class but a function.
For instance, you could do this in your module file:
module.exports = cacheUpdateDelay => new ForecastHandler(cacheUpdateDelay);
// OR
module.exports = function(cacheUpdateDelay) {
return new ForecastHandler(cacheUpdateDelay);
};

Use Singleton Throughout All Node.js Modules

I want to somehow create a global singleton module. I'm using it as the context module where I can reference it in any of my modules.
I'll use it to get to my gateway (repository) module for use in other modules like my business object modules etc. So for example let's say I have:
myBusinessModule.js
module.exports = {
find: function(id){
var user = context.userGateway.find(id);
}
};
So I want to be able to use the context singleton to get at other modules in my node app.
Just like the same thing here, this is Java but same concept I want to do something like this in Node.JS: CleanCodeCaseStudy
Based on your comment, to me it looks like you want something like this. Please correct me if i wrongly understood your requirement.
Access with require()
context.js
var context = {};
context.userGateway = require('../path/to/userGateway/module');
module.exports.context = context;
=====================================================================================
//usage in reference file
var context = require('/path/to/context/file');
module.exports = {
find: function(id){
var user = context.userGateway.find(id);
}
};
Access without require()
var context = {};
context.userGateway = require('../path/to/userGateway/module');
GLOBAL.context = context; // makes your context object accessible globally, just like, console, require, module etc.
=====================================================================================
//usage in reference file
module.exports = {
find: function(id){
var user = context.userGateway.find(id);
}
};

How to avoid using global?

I have very small nodejs app. Inside this application I define a model object in app.js like so:
global.model = {
name: 'Foobar'
};
The model is not persisted to any storage but kept in memory all the time. My requirement is, to be able to read and modify this model inside any module of my app.
I read that it is bad practice to use global. What is the better way? Through exports? Can you explain?
You can have a single module that creates and stores the model. Then, any other module that wants to get the model can require() your model module and then call a method on it to fetch the single shared model.
in model.js:
var mymodel = {
name: 'Foobar'
}
module.exports.getModel = function() { return mymodel;}
in any other module that wants to get the model:
var mymodel = require('./model').getModel();
If your model module would not generally be used for other things, then you could simplify it like this:
var mymodel = {
name: 'Foobar'
}
module.exports = function() { return mymodel;}
in any other module that wants to get the model:
var mymodel = require('./model')();

Nodejs naming conventions for modules

Given this pattern :
A module defines a public API, but needs runtime information.
// Contrived example for a module abstracting a db
module.exports = function (host, schema, ...) {
// A "module-level", private, instance of an object
// that will be used by the public API of the module
var connection = getConnection(host, schema, ...);
return {
queryItems : function (arg) {
// Something that uses both the "module" level instance
// and runtime args.
return connection.query(... arg ... );
}
}
};
Another module will have to require it, than "instanciate" the module, and
use it.
// Module "bar"
var db = require("db"),
xxx = db("myhost", "myschema");
xxx.queryItems("Test"):
In "traditionnal" OO, the first module would expose a class constructor, and by conventions those
have a first capital letter, so you would write
var Db = require("db"),
db = new Db("....", "....");
And there is not ambiguity ; the meaning of "var cat = new Cat()" is pretty accepted ; "var felix = new Cat()" would only be used in case of multiple instances.
Is there a "canonical" / "idiomatic" way, in nodejs, to name such a module exposing functions, and the object that was returned by this function ?
(Sorry if too subjective, I'm looking for the "established" convention rather than a "best" one.)

Resources