Tommy
Tommy

Reputation: 850

How to load requireJS module instantly the moment it is included

I want to use a module twice on one page, each time with different data. In my case I require the module in a mustache template, which is used 2 times, for example:

{{> template-requiretest }}
{{> template-requiretest }} 

In my mustache template I got something like this:

<script>
    var data1 = [x,y,z];
    var data2 = [x,y,z];
    var theId = (some random id);

    require(['app/myApp'], function(myApp){
        myApp.init();
    });
</script>

With the init function call I expected "myApp" to be running twice, instantly with data1 array once and data2 array another time, but the "myapp.init()" only runs once, which I simply tested with a console.log inside "myApp".

Is the code simply wrong or do I missunderstand how AMD/requireJS works?

EDIT: Further testing:

var random = Math.floor((Math.random() * 1000) + 1);
var el = document.getElementById('someId');
el.id += '-'+random;
var theId = el.id;
console.log("ID, set in mustache: ",theId);

require(['app/myApp'], function(myApp){
    console.log("ID, logged inside reqJS:",theId);

    myApp.init();
});

And the console output is this:

xyz.html:131 ID, set in mustache:  someId-428
xyz.html:181 ID, set in mustache:  someId-248
myApp.js:3 ##### running the script now #####
myApp.js:4 ##### using ID: someId-248  #####
xyz.html:134 ID, logged inside reqJS: someId-248
xyz.html:184 ID, logged inside reqJS: someId-248

This indicates, that the module is loaded, after the mustache template got loaded 2 times, then it is running the script of myApp.js twice, but only with the last generated id.

Upvotes: 0

Views: 98

Answers (2)

David Knipe
David Knipe

Reputation: 3454

Calling require(['app/myApp'], function(myApp){ ... }); multiple times only causes app/myApp to run once. So any two such calls will give the same object; if you try to treat them as separate objects with different IDs it won't work. If you want separate objects, do something like this:

require(['app/myApp'], function(MyApp){
    var myApp = new MyApp();
    myApp.init(theId);
});

and, of course, change the script app/myApp so that it returns a constructor for an app instead of the app itself.

Upvotes: 0

Louis
Louis

Reputation: 151380

Each time you execute require(['app/myApp'], function(myApp){, RequireJS notes that you want to execute a callback once app/myApp is loaded. If the module has not yet been fetched, RequireJS will initiate a fetch, record the callback and then, in the future when the fetch is over and the module instantiated, it will call the callback. If multiple requests for the same module come before the module has been instantiated, RequireJS merely keeps track of the callbacks it will need to call when the module is finally ready to be used. Your logs show this is what happens in your case.

I think what you'd intuitively expect or would like is this sequence of execution:

  1. var theId = el.id; executes, setting theId to someId-428.
  2. require(['app/myApp'], function(myApp){ executes.
  3. console.log("ID, logged inside reqJS:",theId); executes, showing someId-428.
  4. var theId = el.id; executes, setting theId to someId-248.
  5. require(['app/myApp'], function(myApp){ executes.
  6. console.log("ID, logged inside reqJS:",theId); executes, showing someId-248.

But the real execution order is like this:

  1. var theId = el.id; executes, setting theId to someId-428.
  2. require(['app/myApp'], function(myApp){ executes and RequireJS initiates the loading of app/myApp, and records the callback to call it in the future.
  3. var theId = el.id; executes, setting theId to someId-248.
  4. require(['app/myApp'], function(myApp){ executes, but the module is not loaded yet so RequireJS adds the callback to those to be called when app/myApp is loaded.
  5. app/myApp finally loads, so the callback is called twice. However, by this time theId has the value someId-248.

Regarding the last step, it is important to node that both callbacks are accessing the same variable. If your code is in a script element like you show earlier in your question then var theId declares a global variable. Forcibly, both callbacks then must be accessing the same variable. It is the same in myApp.init() if you grab the id by accessing the global variable theId.

You could work around the problem with an IIFE, and by passing the id to your myApp.init() invocation, and using the parameter inside the code of that function. So:

(function () {
  var random = Math.floor((Math.random() * 1000) + 1);
  var el = document.getElementById('someId');
  el.id += '-'+random;
  var theId = el.id;
  console.log("ID, set in mustache: ",theId);

  require(['app/myApp'], function(myApp){
    console.log("ID, logged inside reqJS:",theId);

    myApp.init(theId); // Pass the id to your function.
  });
}());

The IIFE makes it so that each time the code above is invoked theId is a new variable scoped to the IIFE. So the callbacks that are invoked by RequireJS each see their own separate variable, with its own separate value.

Upvotes: 1

Related Questions