Aleks
Aleks

Reputation: 5864

Singleton in RequireJS

I want to make a simple singleton using RequireJS.

Something like this:

// js/modules/singleton.js
define([], function () {
    var Singleton = function() {
        this.value = 10;
    }
    return new Singleton();
 });

In my main entry I have the following code:

    // main.js
    require.config({
          paths: {
            singleton: 'js/modules/singleton'
          },
          shim: {

          }
    });

    var o1 = require(["singleton"]);  
    var o2 = require(["singleton"]);

console.log(o1 === o2);     // true
console.log(o1.value);      // undefined (?!)
console.log(o2.value);      // undefined (?!)

o1.value = 20;
console.log(o1.value);      // 20
console.log(o2.value);      // 20

o2.value = 30;
console.log(o1.value);      // 30
console.log(o2.value);      // 30

Variables o1 and o2 were correctly pointing to the same singleton instance (o1 === o2), but why are o1.value and o2.value undefined??

I would expect the attribute "value" to be =10 at this like, since it was so initialized.

Upvotes: 0

Views: 804

Answers (1)

Sirko
Sirko

Reputation: 74076

Your problem is pretty much a race condition.

A simple (synchronous!) call like

var o1 = require(["singleton"]);

returns the module just, if it has previously loaded using the asynchronous version of require().

So to solve your problem, just wrap your code in a async require() call like this:

require( ['singleton'], function( singleton ){

    o1 = singleton;
    o2 = singleton;

    console.log(o1 === o2);     // true
    console.log(o1.value);      // 10
    console.log(o2.value);      // 10

    o1.value = 20;
    console.log(o1.value);      // 20
    console.log(o2.value);      // 20

    o2.value = 30;
    console.log(o1.value);      // 30
    console.log(o2.value);      // 30
});

Example Fiddle

Citing the RequireJS documentation (highlighting added):

Console debugging: If you need to work with a module you already loaded via a require(["module/name"], function(){}) call in the JavaScript console, then you can use the require() form that just uses the string name of the module to fetch it:

require("module/name").callSomeFunction()

Note this only works if "module/name" was previously loaded via the async version of require: require(["module/name"]). If using a relative path, like './module/name', those only work inside define

Upvotes: 1

Related Questions