How to avoid using global variables in Nodejs? - node.js

I have /bin/www that I execute and websocketServer.js that needs the httpServer object from /bin/www to initialize the websocket server. How can I pass httpServer to websocketServer.js without using a global variable?
websocketServer.js:
let WebSocket = require('ws')
let wss = new WebSocket.Server({ server: global.httpServer })
wss.on('connection', (connection, req) =>
...
/bin/www:
let app = require('../app')
let http = require('http')
...
global.httpServer = http.createServer(app)
httpServer.listen(port)
...
I have foo.js and bar.js that both handle user information that is only persistent at runtime (no need to store in database). How can these 2 files work with the same users? I can only think of using a shared variable aka global. Is there any way to avoid using a global variable in this situation? Should I even bother avoiding using global variables if it makes total sense to use them in my mind?
Besides, I came to this situation of needing runtime global variables because so far I've been using a database which is essentially a provider of global variables. Except now my project requires variables that need to be global but don't have to be stored in a database.
foo.js:
...
function getsCalledWhenUserLogsIn(username)
{
global.users[username] = { timer: new Timer(), websocketConnection: null, ... }
// initializing the user below
...
}
...
bar.js:
...
websocketServer.on('connection', (connection, req) =>
{
...
connection.on('message', (message) =>
{
let user = global.users[JSON.parse(message).username]
if (user)
{
user.websocketConnection = connection
...
}
...
}
...
}
...
This is not my code per se but at least it gives you some idea
I want to be able to structure my files in a way that I won't have to use global variables.

Example with global variables:
global.bar = 'hello world';
function foo1() {
console.log(bar);
}
function foo2() {
console.log(bar);
}
foo1();
foo2();
Example without global variables:
var bar = 'hello world';
function foo1(bar) {
console.log(bar);
}
function foo2(bar) {
console.log(bar);
}
foo1(bar);
foo2(bar);
This is overly simplistic, but the main point is: if you want 2 distinct things to have access to the same object without being aware of each other, you need a 'third thing' to pass this object to the first two things.
Also see: dependency injection.
As for the question if you should always do this... I would argue that avoiding globals is something you should always strive for, unless you have a good reason not to. Best practices are a good default, but break them if common sense dictates that you shouldn't apply it for specific cases.
However, I don't think that you have a valid enough case for it here. You just have to learn functions and arguments a bit better.

To avoid global variables you could use XMLHttpRequest and just GET/POST to yourself. Not the most efficient thing but it would still work.
var xhr2 = new XMLHttpRequest();
xhr2.open('GET', "http://yourserver", true);
xhr2.onreadystatechange = function() {
if (this.status == 200 && this.readyState == 4) {
if(this.responseText == '') { return;}
//your code here
}//
};//end onreadystate
xhr2.send();
You could also have global arrays that have objects and just go through them. Then you have one array. It just depends how you want to go about it.

Related

Node setInterval to modify global variable and access it from other module

I need to check every 4 seconds if an ip is alive.
I'm using a global variable global.baseip (I know it's bad practice, I am only trying it out with setInterval)
global.baseip = "http://10.***.**.**:8048/TESTDEV02/ODataV4/Company('****')";
setInterval(function(){
getip();
console(baseip); //this gives the correct value
}, 4000);
var getip = function() {
var hosts = [["10.***.**.**", 8048]];
hosts.forEach(function (item) {
var sock = new net.Socket();
sock.setTimeout(2500);
sock
.on("connect", function () {
baseip =
"http://'10.***.**.**':8048/TESTDEV02/ODataV4/Company('****')";
sock.destroy();
})
.on("error", function (e) {
baseip =
"http://'10.***.**.**':8048/TESTDEV02/ODataV4/Company('****')";
})
.connect(item[1], item[0]);
})
}
Then, I use baseip in other modules/files but it's always undefined.
Any help would be appreciated
Don't use a global. Though you may get it to work as you have discovered it is not easy to get it to work and is easy to forget something that causes your code to not work. It is also messing with node's internals and is deliberately working against the way node.js was designed. Node.js was explicitly designed to prevent people from using global variables. Therefore if you want to use global variables you need to somehow work around those protections.
Instead a simpler and more stable way to do this is to use a module.
One thing people don't realise about Commonjs modules is that they are singletons. This is a consequence of the module caching behavior. What this means is that if you import a module into 10 different files then you are not creating ten different objects that represent your module but all 10 files share a single object (the definition of the Singleton design pattern). Note that this works not only in node.js but also other Commonjs based systems like Webpack, React.js (jsx) and Typescript.
The code is really simple. So simple in fact that it makes no sense not to use this method because trying to circumvent the module system is far more complicated:
// shared.js
let shard_object = {
baseip: "http://10.***.**.**:8048/TESTDEV02/ODataV4/Company('****')"
}
module.exports = shared_object;
Note: You can of course write the above much simpler or much more complicated. I wrote it the way I did for clarity
Then you can share the module above with your other modules:
// getip.js
const shared = require('./shared');
var getip = function() {
var hosts = [["10.***.**.**", 8048]];
hosts.forEach(function (item) {
var sock = new net.Socket();
sock.setTimeout(2500);
sock
.on("connect", function () {
shared.baseip =
"http://'10.***.**.**':8048/TESTDEV02/ODataV4/Company('****')";
sock.destroy();
})
.on("error", function (e) {
shared.baseip =
"http://'10.***.**.**':8048/TESTDEV02/ODataV4/Company('****')";
})
.connect(item[1], item[0]);
})
}
module.exports = getip;
and it works as expected:
// main.js
const getip = require('./getip');
const shared = require('./shared');
setInterval(function(){
getip();
console(shared.baseip); // this gives the correct value
}, 4000);
Because you define another variable with the same name inside the scope, you are in reality making changes to that variable.
Just get rid of it, so you can work with the real baseip.
var getip = function() {
//var baseip; //This variable is overshadowing your global variable
var hosts = [["10.***.**.**", 8048]];
hosts.forEach(function (item) {
var sock = new net.Socket();
sock.setTimeout(2500);
sock
.on("connect", function () {
baseip =
"http://'10.***.**.**':8048/TESTDEV02/ODataV4/Company('****')";
sock.destroy();
})
.on("error", function (e) {
baseip =
"http://'10.***.**.**':8048/TESTDEV02/ODataV4/Company('****')";
})
.connect(item[1], item[0]);
})
}

What is good pattern to share an object between modules in Nodejs?

My situation is that I'm working with Websocket, and there is only one websocket server and lot of methods need to get data from server and modify things on server, i.e. delete inactive sockets, etc.
Right now I'm simply passing server instance through function calls and wrapper functions which is getting tedious and is error prone to everything (cyclic dependencies, typos, etc)
Importing server instance causes circular dependencies.
Passing them through parameters causes too much interdependence.
Ex:
onConnection -> attaches events
onMessage = msgHanlder(server);
...
then in msgHandler there are multiple events to take care of
onNewMsg = newMsg(server)
onDelete = delete(server)
onRequest = request(server)
It's very functional style programming but it's too much pain.
Create a caching module ( get,set method ) and require this module to manage your state between different modules.
cache.js
let _cache = {};
module.exports = {
"get":function(key){
return _cache[key];
},
"set":function(key,value){
_cache[key] = value;
}
}
a.js
const cache = require('./cache');
const b = require('./b');
cache.set('a','value set in a');
b.invoke();
b.js
const cache = require('./cache');
module.exports = {
"invoke":function(){
console.log("Module A: ",cache.get('a'));
}
}

nodejs referenceerror on nested function calls using async.series and async.until

I'm new to nodejs and trying to learn the basics by rebuilding an existing i2c sensor system.
Got it all running using a named functions and async.series inside a single file. To keep make reusable i now want to create a class which i then can import. unfortunatly i get some errors i don't understand.
class.js
const async = require('async');
const i2c = require('i2c-bus');
class Sensor {
constructor (channel) {
this.channel = channel;
var self = this;
}
openBus (callback) {
bus = i2c.open(self.channel, (err) => {callback()}); // shorted for stackoverflow
}
closeBus (callback) {
bus.close( (err) => {callback()}); //also shorted for better readability
}
connection (callback) {
/* first variation */
async.series([openBus, closeBus], callback);
connection2 (callback) {
/* second variation */
async.series([this.openBus, this.closeBus], callback);
}
}
module.exports = K30;
when i import the class, i can without any problem create a new sensor 'object' and call the functions directly using:
> var Sensor = require('./class.js');
> var mySensor = new Sensor(1);
> mySensor.openBus(foo);
> mySensor.closeBus(bar);
but if i go an try call the wrapper-functions, i get the following errors:
> mySensor.connection(foo);
ReferenceError: openBus is not defined (at 'connection')
> mySensor.connection2(foo);
ReferenceError: self is not defined (at 'openBus')
i believe those errors occure due to my lack of understanding the correct usage of this and self. sadly i can't find any good ead on that topic. any help is highly appreciated.
UPDATE
the solution provided in the first two anwsers was in fact my first approch before starting to use "self" (after some googling [this-that-trick]).
anyways, here is the output/error i get using "this.channel" instead:
> mySensor.connection2(foo);
TypeError: Cannot read property 'channel' of undefined (at openBus)
This is not saved anywhere var self = this; and therefore is lost when the function (constructor is function) ends.
Just remove the above line in constructor and use everywhere the this instead of self.
Its true that this keyword is little tricky in javascript, but if you follow reasonable approach, you should be fine.
You indeed have issue with this and self
Every member inside the class has to be referred by this. If you declare a variable named var EBZ-Krisemendt = "SO user";, to access it, you need to use it with this, eg: console.log(this.EBZ-Krisemendt);
What you need here is
openBus (callback) {
bus = i2c.open(this.channel, (err) => {callback()});
}
and then mysensor.connection2(foo) will work fine.
while i still don't fully understand the reason behind this i fixed my code by getting rid of that "ES6" class definition.
class.js
const i2c = require('i2c-bus');
const async = require('async');
function Sensor(channel) {
let that = this; // make 'this' available in sub-function scope
this.channel = channel;
function openBus(cb) {
// open the bus-connection
bus = i2c.open(that.channel);
}
function closeBus(cb) {
// close the bus-connection
}
function connection(cb) {
async.series([openBus, closeBus], cb);
}
function getReading(cb) {
async.until(
function() {
// loop condition e.g. max tries to get reading
},
function(cb) {
connection(cb); // calling nested synchronous connection-routine
},
function (err) {
// result handling
}
); // end async.until
} // end getReading
return {
getReading: getReading
} // make only 'getReading' available
}
module.exports = {
Sensor: Sensor
} // make 'Sensor' available
in the 'member'-functions i can now use the 'class'-variables of 'Sensor' by accessing them with 'that' (e.g.: 'that.channel')
Detail:
function openBus(cb){
bus = i2c.open(that.channel);
}
if i'd use this instead of that it would only work while calling openBus directly. in my example it's neccessary to call openBus and closeBus in a synchronous manner (for obvious reasons). since async.series is additionally nested inside async.until (sensor might need several tries to response) the scope of this changes. by using that instead i'm able to ignore the scope.
Comment:
since the solution is kinda generally pointing to using nested async-calls inside custom modules i'll slightly alter the titel of the initial question. i'm still hoping for better solutions and/or explanations, so i won't mark my own anwser as accepted yet.

RequireJS module for SignalR

Rather than copy and pasting my code onto here, I have uploaded it to github. The RequireJS module does have a dependency on jquery.signalr and in tern has a dependency on jquery but also have a dependency on the javascript held in /signalr/hubs. There is a bit of config to do with Require.Config.
Basically what is happening is on the first time you load the page the connection is made to the hubs within signalr and the "server side" code is executed and does the desired thing. When you refresh the page it does not. All client side code is called, so for example:
var myViewModel = new MyViewMode();
myViewModel.init();
and within your init method you have
var connection = $.connection.myHub;
this.init = function() {
connection.server.myMethod();
}
this would then go off to
public MyHub : Hub
{
public void MyMethod()
{
Client.Request.populateSomeInformation() // I think it's request but I'm doing this from memory!
}
}
and then call
connection.client.populateSomeInformation = function () { .. )
but doesn't call this :(
It looks like a connection has been made (using the good old console.log() to see what it outputs) and indeed debugging the project it executes the code within the hub but there is no response made back to the javascript.
So wonderful people of the internet, where am I going wrong? Do I need to check the state of $.connection.hub.start(); before attempting to start it again?
Time for beer :)
I believe it should be
connection.client.populateSomeInformation = function () { .. )
(not connection.server)
http://www.asp.net/signalr/overview/hubs-api/hubs-api-guide-javascript-client#callclient
(observations on the code you have on github right now)
var isLoaded = false;
// ... some code that doesn't change isLoaded ...
if (isLoaded == false) {
scrollIntervalId = window.setInterval(function () {
signalRLoaded();
}, 30);
}
I think isLoaded will always be false at this point. Not sure what you intended this to accomplish.
var connection = $.connection.hub.start();
I don't think you're supposed to open the connection before defining any client functions. I don't see any client functions being defined here, so maybe you're doing that somewhere else? I don't know if it really matters other than if the server attempts to call a client function that hasn't yet been defined...
function SignalRReady(callback) {
if (isLoaded) {
callback(connection);
} else {
readyCalls = callback;
}
return SignalRReady;
}
SignalRReady.version = "1.0.0";
SignalRReady.load = function(name, request, onLoad, config) {
if (config.isBuild) {
onLoad();
} else {
SignalRReady(onLoad);
}
};
return SignalRReady;
I'm confused by this bit of code, probably because I don't see how it's being used. Is this an attempt at a kind of singleton? I see that SignalRReady is the "class" being returned for the module. You're not really returning an object, you're returning a constructor which implies that you're instantiating it in other places, something like
define(['SignalRReady'], function(sigR)
{
var srr = new sigR();
});
But then you have that load function defined that calls the constructor and makes this look all weird. How are you using this?
Anyways, I'm thinking you might be hitting some kind of race condition where the client function may not always be available at the time the server is trying to call it.
(additional comments/code 2013-09-06)
Your connection object is actually a jQuery promise ( http://api.jquery.com/category/deferred-object/ ).
If you're unfamiliar with promises, think of them generically as a queue of callbacks to be executed later. In this case, when connected, all the callbacks will be executed (in the order they were added). If a callback is added after being connected, it will get executed immediately. This is how your code is working now. You add the callback to the .done queue after the connection is made and is executed immediately.
If you insist on creating the connection object yourself, then you do not need to use the stateChanged event. You just add the callback to the .done queue:
define(function()
{
function signalRReady(callback)
{
if (window.connection == undefined) {
window.connection = $.connection.hub.start();
}
window.connection.done(callback);
}
signalRReady.version = "1.0.0";
return signalRReady;
});
However, I believe it's not a good idea to initiate the connection yourself. Because your module isn't a complete wrapper around SignalR such that people would only use your module to do SignalR stuff, you are not guaranteed (and cannot expect) other code will not initiate the connection. Especially if someone is adding your module to an existing codebase.
Your module is simply adding a new event, so keep it simple. Take the callback and execute it yourself when appropriate:
define(function()
{
function signalRReady(callback)
{
$.connection.hub.stateChanged(function (state)
{
if(state.newState === $.signalR.connectionState.connected)
{
callback();
}
});
}
signalRReady.version = "1.0.0";
return signalRReady;
});
Nowadays, promises are pretty popular. You might want to implement a promise-based module like:
define(function()
{
var deferred = $.Deferred();
$.connection.hub.stateChanged(function (state)
{
if(state.newState === $.signalR.connectionState.connected)
{
// executes all callbacks attached by the "ready" function below
deferred.resolve();
}
});
return {
ready: function(callback)
{
deferred.done(callback);
},
version: "1.0.0"
};
});
If callbacks are attached after the connection has been made, they are executed immediately.
Also, notice this example module's init function returns an object instead of a function. Since RequireJS will pass the same instance around to any module that requires it, state is maintained - we can use local variables instead of global.

Namespacing a javascript library, as optional

I'm about to start building a JS library that will have multiple modules. Let's suppose the library is called Library, and two modules will be called One and Two. I'd like for end users to be able to call the library in two different ways:
Library.One.somefunction(params)
or
somefunction(params)
Basically, I want to give the end users the option of including a namespace or not. Is there a good way to do this? Also, is there a good way to do this if I also want to provide a minified version of the library? This library is something that I could end up in Node.js; for now, I'm going to use it myself, but I want to design it in such a way that it's not too hard to turn in to a sharable project in the future.
Any references you can point me to would be great, thanks!
If you're using Node.js you could leverage the CommonJS module system.
math.js (your library)
exports.add = function() {
for (var i = arguments.length; i--;) {
sum += arguments[i];
}
return sum;
};
program.js (someone using it...)
var MyMath = require('math');
console.log(MyMath.add(1, 2)); // 3
// ... in different ways
var add = require('math').add;
console.log(add(1, 2)); // 3
The basic idea behind making a "namespace" optional is to assign the functions to the global scope, which is the window object:
window.somefunction = Library.One.somefunction;
You can write an include function that works similar to other languages:
var include = function (library, p) {
if (!p) {
for (var prop in library) {
if (library.hasOwnProperty(prop)) {
window[prop] = library[prop];
}
}
} else {
window[p] = library[p];
}
};
Then just do, as required:
include(Library.One);
Or use particular functions only:
include(Library.One, 'somefunction');
Warnings:
Executing the functions without the dot notation (One.somefunction) will cause the this keyword to refer to window rather than Library.One. This isn't a problem if you don't use this at all. If you have data to share to between functions then you can do so using closure scope instead of this:
var Library = {};
(function () {
// I'm a closure, I have local scope
var sharedData = "I'm shared but private to this scope";
Library.One = {};
Library.One.funcOne = function () {
alert(sharedData);
};
Library.One.funcTwo = function () {
sharedData += "!";
};
}) ();
Others have well-advised not to make your methods global. This is because once it is global, it is global for all files, and therefore likely to conflict with other code. What you can do is modify the import function above to create a new object, and assign everything to that object before returning it. Then files that need shortcuts to particular libraries can do:
(function () {
var _ = include(Library.One); // This stays within this scope
_.somefunction();
})();
well, i don't know what you mean by "good way".
First of all, the whole purpose of a namespace is to collect variables that are related and not scatter them all around your public namespace.
Personally I wouldn't use such a thing, but you could loop through your namespace's objects and attach them to the window :
for(var i in Namespace)
if(Namespace.hasOwnProperty(i))
window[i] = Namespace[i];
You could do this pretty easily, but are you certain you want to make all the methods global properties?
You could implement it like this (very simplified):
(function( window, undefined ) {
// Your code setting up namespaces
var Library = {One:{},Two:{}};
// function for adding library code to both namespaces.
// Could be modified to accept an Array of functions/names
function addToLibraryOne( id, fn ) {
window[id] = Library.One[id] = fn;
}
// add a function
addToLibraryOne( "somefunction", function( params ) {
// function code
});
window.Library = Library;
})( window );
I'd wonder if you really want to pollute the global namespace like this.
At the very least, I'd make the global properties an option, then only have the function add those if that option is selected.
Well, the second one means that you also want the functions and object and whatever in your modules to be in the global scope. Entirely possible of course, but so against best practices as to be somewhat abhorrent.
For the first part, just declare your Library namespace globally:
var Library = {};
and then start populating it with your modules:
Library.One = {};
Library.Two = {};
and then start adding the functionality to those modules.
(function($) {
var $.froobString = function(s) { .... };
...etc...
})(Library.One);
(Here I've done it as a self-executing anonymous function that passes in Library.One as $.)
To convert all that to globals, have a routine like this:
var convertToGlobals = function(module) {
for (name in module) {
window[name] = module[name];
}
};
convertToGlobals(Library.One)
But then again I'd advise against it.
I might be wrong about this (so this might get downvoted, but I want this evaluated), but I think you are setting up a contradiction with the requirements
1) I want to use namespaces
2) I want to be able to access namespace functionality without the namespace.
basically 2 is "I dont want namespaces".
For implementation, you could just define a bunch of functions globally that route into the namespace, but then why have the namespace to begin with?

Resources