how to create a singleton

456 views
Skip to first unread message

Reza Razavipour

unread,
Nov 18, 2013, 6:38:09 PM11/18/13
to nod...@googlegroups.com
A newbie question...

I have an app that connects and reuses the same connection to a remote database and a connection to a remote soap server.
I want to implement a singleton pattern for each of these. I am used to doing that in C++ and Java but want to know what the standard 
implementation for a Singleton pattern is in node.js.

Any recommendations or references.


Jose G. Quenum

unread,
Nov 18, 2013, 7:05:14 PM11/18/13
to nod...@googlegroups.com
Please check Addy Osmani book, Learning Javascript design patterns. http://addyosmani.com/resources/essentialjsdesignpatterns/book/
It has a correct version of singleton implementation

--
--
Job Board: http://jobs.nodejs.org/
Posting guidelines: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
You received this message because you are subscribed to the Google
Groups "nodejs" group.
To post to this group, send email to nod...@googlegroups.com
To unsubscribe from this group, send email to
nodejs+un...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/nodejs?hl=en?hl=en
 
---
You received this message because you are subscribed to the Google Groups "nodejs" group.
To unsubscribe from this group and stop receiving emails from it, send an email to nodejs+un...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Reza Razavipour

unread,
Nov 18, 2013, 7:40:00 PM11/18/13
to nod...@googlegroups.com
Wonderful book, thank you.

So reading the book, if I put the code for the mySingleton class into a file on its own, call it single.js. 
In my main.js, I add that with a require statement, such as var singleton = require('./.single);
when I say, singleton.getInstance(), I get a compile error saying singleton does not have a getInstance function...

Do I have to add an export to the single.js file I created or what am I missing...

The code is as follows:

var mySingleton = (function() {

var instance;


function init() {


var privateRandomNumber = Math.random();


return {


publicMethod : function() {


console.log("The public can see me!");


},


publicProperty : "I am also public",


getRandomNumber : function() {


return privateRandomNumber;


},


getInstance : function() {

if (!instance) {


instance = init();


}

return instance;


}

};

};

return {

getInstance : function() {


if (!instance) {


instance = init();


}

return instance;

}

};

})();



Thanks for the help.

Reza


Jose G. Quenum

unread,
Nov 18, 2013, 8:02:11 PM11/18/13
to nod...@googlegroups.com
yeah that's right. You just need to add the line 
module.exports = mySingleton
and in the caller file require as follows
var singleton = require('./single').mySingleton

Hope that helps
José

Reza Razavipour

unread,
Nov 18, 2013, 8:30:23 PM11/18/13
to nod...@googlegroups.com
Awesome that works wonderfully. Thanks.

One more issue that you have an idea on, is that in getInstance I have to make an async call. It creates a soap connection and that is only supported in async mode.
Any thoughts on how to structure that code?



On Monday, November 18, 2013 3:38:09 PM UTC-8, Reza Razavipour wrote:

Jose G. Quenum

unread,
Nov 18, 2013, 8:43:52 PM11/18/13
to nod...@googlegroups.com
I guess you can do it in getInstance or init but you're gonna need to pass a callback to support the async mode

Reza Razavipour

unread,
Nov 18, 2013, 8:47:46 PM11/18/13
to nod...@googlegroups.com
I could then it would get ugly, because now whoever calls getInstance have to provide a callback.

If only I could turn the async to a sync call....

Jose G. Quenum

unread,
Nov 18, 2013, 8:52:26 PM11/18/13
to nod...@googlegroups.com
you could add a default callback if the caller just passes null. But if you're gonna make a soap connection I think the async mode is just appropriate

dhtml

unread,
Nov 20, 2013, 2:37:09 PM11/20/13
to nod...@googlegroups.com


On Monday, November 18, 2013 3:38:09 PM UTC-8, Reza Razavipour wrote:

Factory Method

function getAnObject(a) {
  var anObject;
 
  var b = a + 1;
 
  return (getAnObject = function() {
    if(! anObject ) {
      anObject = {name: b};
    }
    return anObject;
  })();
}


Eager Initialization

var anObject = new function(a) {
  var b = a + 2;
  this.name = b;
};

From https://noisebridge.net/wiki/JavaScript/Notes/Singleton

Class is Friday, 7pm, at Noisebridge.

Oh yeah, and in case you were wondering, it's fre.

Gregg Caines

unread,
Nov 21, 2013, 10:13:48 AM11/21/13
to nod...@googlegroups.com
The singleton pattern is actually unnecessary in most languages outside of java, including javascript.  You should be wary of any javascript book that tries to teach you singletons at all.  Many of those gang of four patterns simply don't translate outside of java and c++ (eg if you want to implement command, strategy, or factory patterns, you should really first check out javascript's first class functions.).

So how do you achieve the same effect in javascript?  In the browser, you have globals.  If you want just one instance of a thing, create it, and set it to a global variable.  You can use that global variable everywhere.  (If you're thinking "but global variables are bad!", I mostly agree.  This is one of the reasons that the singleton itself is actually considered an anti-pattern by many.

In node, the module system is a global namespace that can maintain state, so that's the appropriate way to achieve the same effect.  I do this in node applications all the time.  For example, if I have a module for emailing with a send() method on it, I don't have it export a constructor; I have it export an object.  That object might maintain some state or it might not.  When the module is subsequently require()'d, it will have any state that it has accumulated since.

All of this is a bit hairy because we're talking about global state (which is the main impetus for singletons, when you get right down to it).  Whatever you decide to do though, keep in mind that writing idiomatic code in any language means using the features of that language, and not translating java/C++ idioms into it.  It will be an extremely rare javascripter that will want to work on your code if you've got singletons in it.

G




On Monday, November 18, 2013 3:38:09 PM UTC-8, Reza Razavipour wrote:

Kamil Leszczuk

unread,
Nov 21, 2013, 10:33:44 AM11/21/13
to nod...@googlegroups.com

> For example, if I have a module for emailing with a send() method on it, I don't have it export a constructor; I have it export an object.  That object might maintain some state or it might not.  When the module is subsequently require()'d, it will have any state that it has accumulated since.

For.most of the time, that's unnecessary - multiple require() calls for the same module return same, cached module, so you can store state just by using local variables in that module.

Gregg Caines

unread,
Nov 21, 2013, 10:36:05 AM11/21/13
to nod...@googlegroups.com
Yeah... that's what I'm saying :)

G


On Thu, Nov 21, 2013 at 7:33 AM, Kamil Leszczuk <kami...@gmail.com> wrote:

> For example, if I have a module for emailing with a send() method on it, I don't have it export a constructor; I have it export an object.  That object might maintain some state or it might not.  When the module is subsequently require()'d, it will have any state that it has accumulated since.

For.most of the time, that's unnecessary - multiple require() calls for the same module return same, cached module, so you can store state just by using local variables in that module.

--
--
Job Board: http://jobs.nodejs.org/
Posting guidelines: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
You received this message because you are subscribed to the Google
Groups "nodejs" group.
To post to this group, send email to nod...@googlegroups.com
To unsubscribe from this group, send email to
nodejs+un...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/nodejs?hl=en?hl=en
 
---
You received this message because you are subscribed to a topic in the Google Groups "nodejs" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/nodejs/GmUto9AN47U/unsubscribe.
To unsubscribe from this group and all its topics, send an email to nodejs+un...@googlegroups.com.

Kamil Leszczuk

unread,
Nov 21, 2013, 10:37:32 AM11/21/13
to nod...@googlegroups.com

Aah, nevermind then, I misunerstood ;)

You received this message because you are subscribed to the Google Groups "nodejs" group.
To unsubscribe from this group and stop receiving emails from it, send an email to nodejs+un...@googlegroups.com.

Reza Razavipour

unread,
Nov 21, 2013, 11:34:14 AM11/21/13
to nod...@googlegroups.com
this I get the jist of the conversation but my Javascript skills, less than 2 months, does not allow me to be able to code this up.
Also, as a starter in the new language the last thing I want to do is to miss out on the language correct way of things and force lets say the Java way of doing things in JS.

Can you show me a skeleton of such function and a tiny consumer of that? The reason I say that is the fact that all of the examples are all done in the same JS file and not setup as module and when I try to change to a module and a consumer, I run into syntax problems and ....

I do not understand the difference between a class exporting an object as opposed to a constructor


Thank you so much for showing me the correct way

Reza Razavipour

unread,
Nov 21, 2013, 12:03:58 PM11/21/13
to nod...@googlegroups.com
Ok so this is the way i have it constructed... SoapClient is my module and I want it to be used as a singleton, i.e. if it is initialized, it just returns the connection, or SoapClient.instance...

var SoapClient = function() {

var soap = require('soap');
this.init = function (){
var url = "http://172.31.19.39/MgmtServer.wsdl";
var endPoint = "https://172.31.19.39:9088";
var options = {};
options.endpoint = endPoint;
soap.createClient(url, options, function(err, result) {
if (err) {
console.log('soap client create failed ' + err);
return;
}
console.log('init is called ready');
SoapClient.instance = result;
SoapClient.instance.setSecurity(new soap.BasicAuthSecurity(
'admin-priv', 'password'));
});
};
};
SoapClient.getInstance  = function () {
if (SoapClient.instance) {
return SoapClient.instance;
}
new SoapClient().init();
return SoapClient.instance;
};
SoapClient.instance = null;
module.exports = SoapClient;


Thoughts

Brian Di Palma

unread,
Nov 21, 2013, 12:14:27 PM11/21/13
to nod...@googlegroups.com
I guess instead of exporting the constructor you could export a
function which checks if an instances has been created and if not
create it.

If you don't want to write it as a function call, you could try set a
getter on the exports and just execute the same logic in the getter.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

Documentation from MDN in case you are not familiar with property
getters/setters in JS...they are not what you'd be used to from Java.

Rick Waldron

unread,
Nov 21, 2013, 12:50:29 PM11/21/13
to nod...@googlegroups.com
I recommend being wary of any broad generalizations about programming patterns :P

Rick


Gregg Caines

unread,
Nov 22, 2013, 11:28:17 AM11/22/13
to nod...@googlegroups.com
I'm not 100% sure of your requirements, but this is what I assume you're after:

-------------------------------------------------
file : soapClient.js

var memoizedClient;
var
soap = require('soap');
var create = function (cb){
  if (memoizedClient){
    return cb(null, memoizedClient);
  }
  var url = "http://172.31.19.39/MgmtServer.wsdl";
  var endPoint = "https://172.31.19.39:9088";
  var options = {};
  options.endpoint = endPoint;
  soap.createClient(url, options, function(err, result) {
    if (err) {
      return cb(null, memoizedClient);   // pass errors properly! :)
    }
    setSecurity(new soap.BasicAuthSecurity('admin-priv', 'password'));
    memoizedClient = result;
    cb(null, result);
  });
exports.create = create;
exports.client = memoizedClient;  // I don't do this, but I think it's what you're looking for

---------------------------------------------
file: someClientCode.js

var client;
require('soapClient').create(function(err, client){
  // do stuff here
});
---------------------------------------------

ALSO:
If you're somehow sure that you've already called create() previously, you could just do:


var client = require('soapClient').client;
// do stuff here

I know that's a hell of a lot prettier, but I usually don't do that because I like to not
have to worry about whether i've called create() or not.  I just call create() everytime, and
suck up the fact that there's a callback.  In the cases that I'd use this pattern like you are
using it, it's ONLY because I'd like to not have to incur the network cost of the asynch call
everywhere I use it, and not because I want fewer indentations in my code.  I do this with
database connection pools as well, for example, because those shouldn't be created over
and over for every use.  So in short, ALL of this hinges on my assumption that
"soap.createClient" involves a network call that you don't want to repeat everytime you
want to make a soap request.  Otherwise, there's no good reason to memoize (cache state).

Often I put a setter on the memoizedClient as well because it works nicely for dependency
injection in unit tests.

Soooo... I think I have to admit in retrospect that this is indeed a singleton.  At least this
way you can be more idiomatic than any general javascript singleton code I've seen.

(I never ran any of this code, so it's probably broken in 14 ways)

Hope that helps,
G

Reza Razavipour

unread,
Nov 22, 2013, 11:39:17 AM11/22/13
to nod...@googlegroups.com
thanks for the response. I will have to 'digest' it but I get the idea you are laying out.
My original intent is for the consumer of this object is to use the "client" synchronously on demand, as opposed to async.


On Monday, November 18, 2013 3:38:09 PM UTC-8, Reza Razavipour wrote:

dhtml

unread,
Nov 27, 2013, 12:50:33 AM11/27/13
to nod...@googlegroups.com


On Thursday, November 21, 2013 7:13:48 AM UTC-8, Gregg Caines wrote:
 
So how do you achieve the same effect in javascript?  In the browser, you have globals. 

The global object has nothing to do with web browsers.
 
If you want just one instance of a thing, create it, and set it to a global variable.  You can use that global variable everywhere.  (If you're thinking "but global variables are bad!", I mostly agree.  This is one of the reasons that the singleton itself is actually considered an anti-pattern by many.

Singleton is necessary when the program must have at most one instance of an object; where having two would be a problem. In javascript, it's well-used where the initialization of that one object needs some variables or configuration to initialize itself.

Ryan Schmidt

unread,
Nov 27, 2013, 4:28:08 AM11/27/13
to nod...@googlegroups.com

On Nov 26, 2013, at 23:50, dhtml wrote:

> On Thursday, November 21, 2013 7:13:48 AM UTC-8, Gregg Caines wrote:
>
>> So how do you achieve the same effect in javascript? In the browser, you have globals.
>
> The global object has nothing to do with web browsers.

Sure it does. In browsers you can reference a global easily from any file. In node, each file gets its own namespace, so you can’t.

Gregg Caines

unread,
Nov 27, 2013, 4:43:32 AM11/27/13
to nod...@googlegroups.com
Sure that's the common explanation, but don't fall for it: globality has everything to do with it.  If the singleton didn't care about creating global state, it could just have `this.created = true;` for its *only* internal state and have thrown exceptions from the constructor for any subsequent calls.  That's the simplest way to ensure that only one instance gets constructed.

In the browser, where there's no module system to stop your global variables from spraying everywhere, any singleton can just as safely be replaced by a simple single global instance instantiated normally.  There's absolutely no difference in control or globality whatsoever, and you get better performance by not making completely unnecessary getInstance() calls just to get your instance.

The singleton pattern is really nothing more than a hack to get globals into java via the global class namespace.  Even in java, it's pretty common to solve the same problems with IoC containers now instead of singletons, because global state is generally considered A Bad Thing (unless used extremely judiciously).

G






--

Rick Waldron

unread,
Nov 27, 2013, 1:36:18 PM11/27/13
to nod...@googlegroups.com
This is simply not true. By default, module code has access to the `global` object reference, which allows: 

// module.js
global.foo = 1;


// program.js
require("./module.js");

console.log(foo); // 1


There is no implicit global environment bindings created for top level var declarations or function declarations because the source body of module code is wrapped in an IIFE: https://github.com/joyent/node/blob/master/src/node.js#L1007-L1014. Which is not the same as a unique "namespace" and certainly not the same as having a fresh realm-like global object.

Rick
 

Michael J. Ryan

unread,
Nov 27, 2013, 5:33:25 PM11/27/13
to nod...@googlegroups.com
of course you could just as easy have done...
 
  //foo module ...
  var foo = {...}
  module.exports = foo;
 
  //app.js
  var foo = require(‘foo’)
 
all require(‘foo’) with the same library reference will be the same...
 
 
the only thing global does is allow multiple versions of libraries not to stomp on eachother...
 
  //bar module – first to register wins
  module.exports = global.__bar__ = global.__bar__ || initModule();
 
  function initModule() {
    return {\*...some object...*\};
  }
  ...
 
which can also be valuable
--
--
Job Board: http://jobs.nodejs.org/
Posting guidelines: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
You received this message because you are subscribed to the Google
Groups "nodejs" group.
To post to this group, send email to nod...@googlegroups.com
To unsubscribe from this group, send email to
nodejs+un...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/nodejs?hl=en?hl=en
 
---
You received this message because you are subscribed to the Google Groups "nodejs" group.
To unsubscribe from this group and stop receiving emails from it, send an email to nodejs+un...@googlegroups.com.

Rick Waldron

unread,
Nov 28, 2013, 12:54:05 AM11/28/13
to nod...@googlegroups.com


On Wednesday, November 27, 2013, Michael J. Ryan wrote:
of course you could just as easy have done...
 

Sure, if I was trying to illustrate something that wasn't the thing I was trying to illustrate. Or if I wanted to confuse my point with something questionably relevant.

Rick 

Alex Kocharin

unread,
Nov 28, 2013, 5:33:27 AM11/28/13
to nod...@googlegroups.com

var global_object = function(){return this}()

afair, modules had their own namespace with vm.runInNewContext() some time ago, but it was dropped and/or not the default for performance reasons

Reply all
Reply to author
Forward
0 new messages