Node.js singleton module pattern that requires external inputs - javascript

normally we might create a simple singleton object like so with Node.js:
var foo = {};
module.exports = foo;
or
function Foo(){}
module.exports = new Foo();
however
what is the best way to make a clean singleton module that needs an external variable for initialization? I end up making something like this:
var value = null;
function init(val){
if(value === null){
value = val;
}
return value;
}
module.exports = init;
this way someone using the module can pass in an initializing value for a certain variable. Another way to do it would be like so:
function Baz(value){
this.value = value;
}
var instance = null;
module.exports = function init(value){
if(instance === null){
instance = new Baz(value);
}
return instance;
}
there's two problems I encounter with this:
(1) this is minor, but the semantics is wrong. We can rename init to getInstance, but we can't make the same function literal mean "initialize and get" since they are different meanings. So we have to have a function that does two different things. Create an instance and retrieve and instance. I don't like this especially since in some cases we need to make sure the argument to initialize the instance is not null. With multiple developers using a module it's not clear if a module has been initialized yet, and if they pass in undefined into the module that hasn't been initialized, that could become a problem or just confusing at the least.
(2) this is more important - in some cases initializing Baz is asynchronous. For example, making a Redis connection or reading from a file to initialize a singleton, or making a socket.io connection. This is what really trips me up.
e.g. here is a module that I have that I consider really ugly that stores a socket.io connection:
var io = null;
var init = function ($io) {
if (io === null) {
io = $io;
io.on('connection', function (socket) {
socket.on('disconnect', function () {
});
});
}
return io;
};
module.exports = {
getSocketIOConn: init
};
the above module is initialized like so:
var server = http.createServer(app);
var io = socketio.listen(server);
require('../controllers/socketio.js').getSocketIOConn(io);
So I am looking for a design pattern that allows us to create a singleton module where the initialization process is asynchronous. Ideally we won't have the same function both initializing the instance as well as retrieving it. Does such a thing exist?
I don't think there is necessarily a way to create a pattern that solves this problem but perhaps I am making the mistake of structuring my code in a way that is creating a problem that doesn't need to exist- the problem of initializing a module with a value only once, but using one function to both init the instance and retrieve the instance.

It sounds like you're trying to create a module that gets initialized in one place and then uses some shared resource from that initialization for other users of that module. That is a semi-common need in the real world.
First off, it's ideal if a module can load or create the things that it depends on because that makes it more modular and useful on its own and puts less of a burden on someone using it. So, in your case, if your module could just create/load the thing that it needs when the module is first created and just store that resource in it's own module variable, then that would be the ideal case. But, that is not always possible because the shared resource may be someone else's responsibility to set up and initialize and this module just needs to be made aware of that.
So, the common way to do that is to just use a constructor function for the module. In Javascript, you can allow the constructor to take an optional argument that provides the initialization info. The code responsible for setting up the module would call the constructor with the desired setup parameter. Other users of the module that weren't responsible for setting up the module could just either not call the constructor or if they want a return value or there are other constructor parameters that they should pass, they could pass null for that setup parameter.
For example, you could do this:
var io;
module.exports = function(setup_io) {
if (setup_io) {
io = setup_io;
}
return module.exports;
};
module.exports.method1 = function() {
if (!io) {
throw new Error("Can't use method1 until io is properly initalized");
}
// code here for method1
};
// other methods here
Then, users of the module could either do this:
// load myModule and initialize it with a shared variable
var myModule = require('myModule')(io);
or this:
// load myModule without initializing it
// (assume some other module will initialize it properly)
var myModule = require('myModule');
Note: For developer sanity, it would be useful to have individual methods that require appropriate setup (before they can be used properly) to check to see if the module has been setup when any method is called that needs that setup in order to properly inform a developer that they have called a method before setting up the module properly. Otherwise, errors can happen much further downstream and likely won't have useful error messages.
If you now want the initialization process to be async, that can be done too, but it certainly complicates other uses of the module because they won't necessarily know when/if the module has been initialized.
var moduleData;
var readyList = new EventEmitter();
module.exports = function(arg, callback) {
// do some async operation here involving arg
// when that operation completes, you stored the result
// in local module data and call the callback
readyList.on("ready", callback);
someAsyncOperation(arg, function() {
// set moduleData here
// notify everyone else that the module is now ready
readyList.emit("ready");
// remove all listeners since this is a one-shot event
readyList.removeAllListeners("ready");
});
return module.exports;
};
If you have other users of this module that wish to be notified when it has finished initializing, you can allow them to register a callback themselves to be notified when the module is ready.
// pass a callback to this method that will be called
// async when the module is ready
module.exports.ready = function(fn) {
// if module already ready, then schedule the callback immediately
if (moduleData) {
setImmediate(fn);
} else {
readyList.on("ready", fn);
}
};
If, for reasons I don't quite understand, you want to use the same constructor for both initialization and ready detection, that can be done, though I don't think it's near as clear as just using a separate method for ready detection:
var moduleData;
var readyList = new EventEmitter();
module.exports = function(arg, callback) {
// if both arguments passed, assume this is a request for module
// initialization
if (arguments.length === 2) {
// do some async operation here involving arg
// when that operation completes, you stored the result
// in local module data and call the callback
readyList.on("ready", callback);
someAsyncOperation(arg, function() {
// set moduleData here
// notify everyone else that the module is now ready
readyList.emit("ready");
// remove all listeners since this is a one-shot event
readyList.removeAllListeners("ready");
});
} else {
// constructor called just for a ready request
// arg is the callback
if (moduleData) {
// if module already ready, then schedule the callback immediately
setImmediate(arg);
} else {
// otherwise, save the callback
readyList.on("ready", arg);
}
}
return module.exports;
};
Usage for async initializing the module:
// async initialization form
var myModule = require("myModule")(someArg, function() {
// can use myModule here
});
Usage for loading the module and getting notified when someone else has initialized it:
var myModule = require("myModule")(function() {
// can use myModule here
});

Related

How to reference the calling Javascript module?

I am using what I understand to be the Javascript module pattern, and jQuery.
I have an app which has a public and an admin side. Each has its own JS file, though some functionality is shared so I have extracted it to a common file. Gulp combines the common + public files into a single file for use on the public side, and the common + admin files into a single file for use on the admin side.
The public JS file includes something like:
var PublicFoo = (function () {
var bar = function() {
// ..
};
var init = function() {
$button.on('click', Common.someCommonThing);
};
return {
init: init
};
})();
The HTML page where this code is needed fires it off like so:
<script>
PublicFoo.init();
</script>
The admin JS file includes something very similar, also defining a bar() function, and calling the same Common module function.
var AdminFoo = (function () {
var bar = function() {
// ..
};
var init = function() {
$button.on('click', Common.someCommonThing);
};
return {
init: init
};
})();
The common JS file (shared and combined with both public and admin JS) includes something like:
var Common = (function () {
var someCommonThing = function() {
// Do stuff.
// When done, I want to call bar() in the calling module.
// This does not work, throws 'Uncaught ReferenceError: bar is not defined'
bar();
};
return {
someCommonThing: someCommonThing,
// ...
};
})();
From the Common module, how can I reference a function in the calling module?
I know about .caller, but apparently that is non-standard and should not be used.
I could maybe somehow pass in the name of the calling module as a parameter to Common, and reference it, but that seems ugly:
// In PublicFoo
var init = function() {
$button.on('click', function() {
Common.someCommonThing(PublicFoo)
});
};
// In Common
var someCommonThing = function(callingModule) {
// ...
callingModule.bar();
I could also of course extract the bar() call out and do it back in the calling module, but that doesn't seem so neat either:
// In PublicFoo
var init = function() {
$button.on('click', function() {
Common.someCommonThing();
bar();
});
};
// ... and the same thing in AdminFoo
I feel like this must be JS modules 101, a basic requirement, and yet I can't seem to find anything about it, though I may be searching using the wrong terminology. Or is the reason I can't find how to do this because it should not be done this way?
How can I reference the appropriate bar() from the Common module?
I know about .caller, but apparently that is non-standard and should not be used.
Also it doesn't work in your case, as the caller is the event handler and neither PublicFoo nor AdminFoo.
I could maybe somehow pass in the name of the calling module as a parameter to Common, and reference it
Yes, passing references to the thing that you want to be called is the way to go if you want someCommonThing to do different things after it has finished. Notice you really should only use such a callback when the thing is asynchronous, otherwise just returning and calling bar afterwards (like in your last snippet) is much easier.
How can I reference the appropriate bar() from the Common module?
If both bars might be loaded at once into the page, then there's no way around a parameter that references the callback.
However, that doesn't seem to be the case in your example - on one page, AdminFoo takes the role of Foo and on the other page PublicFoo takes the role of Foo.
So just reference only Foo.bar from Common! Let the respective pages fill it with the appropriate value, i.e.
var Foo = AdminFoo
on the admin page and
var Foo = PublicFoo
on the public page.
Passing functions to other functions is very common and perfectly idiomatic JavaScript, so you could do it like this:
// In PublicFoo
var bar = function() {
// ..
};
var init = function() {
$button.on('click', function() {
Common.someCommonThing(bar)
});
};
// In Common
var someCommonThing = function(bar) {
// ...
bar();
};

How to create a child process from a string

In the browser, we can create workers from a javascript string as follows:
var blob = new Blob([sourceString]);
var url = window.URL.createObjectURL(blob);
var worker = new Worker(url);
Is there any way to do this with node's child process? I have a single JavaScript file I and want to create workers that are coded dynamically.
The source string is a created dynamically at run time.
The closest answer I found was this one, but it requires a seperate file.
If I understood you right, I created a module which does just that yesterday.
It was not intended to create workers from strings but from actual functions even, because the actual function code must be passed thought message, they are stringified to be rebuilt (thought eval()) inside the worker.
And this is done thought the code:
var source = fn.toString();
...so, having that string prototype also has a .toString() method, passing the function as string must work too (and in fact works. I just tested it).
It may not be what you want: If you need to pass in and out messages from and to the worker, this module is not for you. But you can see the code and modify it to fit your needings.
On the other hand, if you only want to execute some function in background and get the result it is much simpler than dealing with worker plumbings because you can pass-in parameters to the function and get the result just as a simple function call.
Example:
// Reauires funwork (`npm install --save funwork`)
var funwork = require("funwork");
var workerfn = funwork(function_src_string); // or actual function.
It has the drawback that the function must be evaluated though eval() but, in your case, (having a string source) I think this is anyway a must.
EDIT: Here is a modified version of funwork to approach what you want as we discussed in comments:
var Worker = require('webworker-threads').Worker;
var Deasync = require('deasync');
function strWorker(fn){
var source = fn.toString();
return function() {
var done = false;
var args = Array.prototype.slice.call(arguments);
var error;
// Create worker://{{{
var worker = new Worker(function(){
var fn;
var me = this;
// Wait for function source and arguments:
me.onmessage = function(event) {
switch (event.data.oper) {
case "src":
// "Compile" function thougt source evaluation.
try {
eval ("fn = " + event.data.msg + ";");
postMessage(['ready']);
} catch (e) {
postMessage(['error', "Error trying to evaluate function source"]);
};
break;
case "args":
// Call the function with given arguments and reset the rest of worker stuff.
try {
// Reset worker (inside) event handler:
delete me.onmessage;
// Notify that worker is ready:
postMessage(["ok"]);
// Start function execution:
fn.apply(me, event.data.msg);
} catch (e) {
postMessage(['error', e]);
};
break;
};
};
});//}}}
// Event handling://{{{
worker.onmessage = function(event) {
switch (event.data[0]) {
case 'error':
worker.postMessage({oper: "end"});
done = true;
error = event.data[1];
break;
case 'ready':
worker.postMessage({oper: "args", msg: args});
break;
case 'ok':
done = true;
break;
};
};//}}}
// Send function source to worker:
worker.postMessage({oper: "src", msg: source});
// Wait (without blocking) until worker executed passed function:
Deasync.loopWhile(function(){return !done;});
if (error) throw error;
// Reset worker (outside) event handler:
delete worker.onmessage;
return worker;
};
};
module.exports = strWorker;
I kept the ability of passing arguments to the function because it is already implemented and you can simply don't use it if you doesn't need to pass anything.
The usage is the same with the only difference that the generated function returns a running worker instead of a function return value.
Used event handlers (inside and outside the worker ) are deleted prior to function (passed in as string) execution and worker returning, respectively, to avoid any side effect and the execution context ("this") of the passed-in function is also set to the actual worker "parent" function. .
If you want a single file js to spin up different processes creating a cluster might be a solution. Here is a pretty good tutorial: Tutorial
Basically node come with native cluster module
var cluster = require('cluster');
You can tell if the process is a master or a worker by cluster.isMaster. If the process is the master process you can spin up workers by doing cluster.fork()
if (cluster.isMaster) {
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
} else {
http.createServer(function(req, res) {
res.writeHead(200);
res.end('process ' + process.pid + ' says hello!');
}).listen(8000);
}
Hope this helps.
As for child process, you can child_process.fork(modulePath[, args][, options]) to run other modules and pass in arguments. The module can do different things according to the argument so it is dynamic... Seems you just want dynamic behavior based on the input and child_process can do it if you can make put the code in a different file. If you can only have one, try the cluster solution.

How to call a method outside a closure

I'm trying to use the NodeJS module "pcsc-lite" to communicate with a card reader. If you want to take a look at the module : https://github.com/santigimeno/node-pcsclite.
I'm looking for a way to send a sequence of data to my reader using my own method. Because, the module is event-based. So I have to declare two listeners (one in the other) to be able to call the send method.
For example :
module.on("reader", function(reader){
//...
reader.on("status", function(status){
//...
reader.connect({ share_mode : this.SCARD_SHARE_SHARED },function(err, protocol) {
//This is the method I want to be able to call "when I need it"
reader.transmit(...);
});
});
});
I would like to call the transmit method like this for example :
function send(...){
reader.transmit(...);
}
I think there is a way to do it, but I seem to be a little bit hooked to my C/Java programming habits.
Thanks in advance.
If your reader will be a singleton, you can declare it outside the callback, and then assign the variable when you're ready. Without knowing more, here's a simple example:
let reader; // we prepare a variable that's outside of scope of it all.
// your `send` function
function send(params) {
let stuff = doStuffWithParams(params);
reader.transmit(stuff, callback);
}
// we take out init stuff too
function initialize() {
// we know reader variable is already initialized.
reader.on('status', function() {
reader.connect({
share_mode : this.SCARD_SHARE_SHARED
},function(err, protocol) {
// send.
send();
// or even better, emit some event or call some callback from here, to let somebody outside this module know you're ready, then they can call your `send` method.
});
});
}
// now your module init section
let pcsc = require('pcsclite')();
pcsc.on('reader', function(r) {
// assign it to our global reader
reader = r;
initialize();
});
Note: don't call your variables module, it's refering to the file being currently executed and you can get unexpected behavior.

Override the require function

Is it possible to override the global require function, affecting it at process level?
From what I know, the require function is provided as argument in the function that wraps the NodeJS scripts:
(function (..., require, __dirname) { // something like this
// The wrapped code
})(...);
Is there any way to modify the require function?
(function () {
var _require = require;
require = function () {
console.log("...");
_require.apply(this, arguments);
};
})();
This will probably affect only the script where it's located.
How can we modify it at the process level?
var Module = require('module');
var originalRequire = Module.prototype.require;
Module.prototype.require = function(){
//do your thing here
return originalRequire.apply(this, arguments);
};
mock-require does this by overriding Module._load (which is what the real require actually calls).
Here is a much safer native ES6 answer based on #orourkedd which acts like an event listener on all require calls, It might look like its replacing require but if you look closer its actually saying: require = require and trap calls to it but return original behaviour. This is just one of the millions of uses of Proxy() which has been really handy for me, for example in Typescript for mapping tsconfig "paths" with the real module node will resolve.
I would go as far as to say that this is not "Monkey patching" as its on a lower level of the language.
var Module = require('module');
Module.prototype.require = new Proxy(Module.prototype.require,{
apply(target, thisArg, argumentsList){
let name = argumentsList[0];
/*do stuff to ANY module here*/
if(/MyModule/g.test(name)){
/*do stuff to MY module*/
name = "resolveAnotherName"
}
return Reflect.apply(target, thisArg, argumentsList)
}
})
This is the workaround I found. If there is any better solution, I'm open to see it.
I created a script named req-modifier.js:
module.exports = function (_args) {
var _require = _args[1];
function newRequire () {
console.log("Require is called");
return _require.apply(this, arguments);
}
newRequire.__proto__ = _require;
_args[1] = newRequire;
};
Then from the files I want to modify the require function, I do:
require("./req-modifier")(arguments);
var foo = require("./foo");
The limitation is that I have to call every time the req-modifier function.

Singleton pattern with Browserify/CommonJS

Trying to implement the singleton pattern within CommonJS modules, using Browserify. So far:
// foo.js
var instance = null;
var Foo = function(){
if(instance){
return instance;
}
this.num = 0;
return instance = new Foo();
}
Foo.prototype.adder = function(){
this.num++;
};
module.exports = Foo();
// main.js
var foo = require('./foo.js');
console.log(foo.num); // should be 0
foo.adder(); // should be 1
var bar = require('./foo.js');
console.log(bar.num); // like to think it'd be 1, not 0
First problem is that I get a maximum call stack exceeded error when I load the built JS file in the browser, but secondly, am I approaching this correctly? Is this possible?
First problem is that I get a maximum call stack exceeded error
Well, that comes from your Foo function recursively calling new Foo…
but secondly, am I approaching this correctly?
No. For singletons, you don't need a "class" with a constructor and a prototype - there will only ever be one instance. Simply create one object, most easily with a literal, and return that:
module.exports = {
num: 0,
adder: function(){
this.num++;
}
};
The result of any require call is a singleton -- whether a singleton instance or a singleton function or a singleton factory function. Furthermore, a require call should be idempotent -- poorly written CommonJS modules may violate this, so if a CommonJS module has a side effect, that side effect should happen only once no matter how many times that require is called.
The code snippet you have
if(instance){
return instance;
}
// ...
return instance = new Foo();
is a legacy of the kinds of hoops you'd have to jump through if you were using plain old JavaScript to create singletons. It's totally unnecessary when using CommonJS and besides that, it leads to your maximum call stack exceeded issue.
Your code could be rewritten like this:
var Foo = function(){
this.num = 0;
}
Foo.prototype.adder = function(){
this.num++;
};
module.exports = new Foo();
or even more succinctly:
module.exports = {
num: 0,
adder: function(){ this.num++; }
}
because putting the adder method on the prototype doesn't gain you any real efficiency if you're only creating a single instance of Foo, and because you don't need to hide anything in the closure.

Categories

Resources