1
votes

requireJS is giving me a headache atm. requireJS is AMD which by definition says it's asynchronous. Normally I would define a module like this.

define("some Name", ["./moduleOne"],function(moduleOne){

  //this would be undefined
  moduleOne.whatEver();  

  var aMethod = function(){
    //user aModule.whatever();
  }

  return {
    method: aMethod;
  }
});

Ok, I got that I can't directly use moduelOne.whatever because it is loaded asynchronous and it's not there if the callback is being called.

First Question, is this correct?

Now if I change the module definition to this:

define("some Name", function(require, exports){

  var moduleOne = require(".moduleOne");      

  //this is OK
  moduleOne.whatEver();  

  var aMethod = function(){
    //user aModule.whatever();
  }

    exports.method = aMethod;
});

I can use aModule.whatever directly. As I read from the docs, using this (commonJS) style, requires parses the function with Function.prototype.toString, sees the require statement and load the modules directly.

I am pretty sure, I am misunderstanding something here and it would be nice of someone could explain how exactly requireJS works and if the second style is really synchronous.

Thanks

1

1 Answers

3
votes

You've misunderstood how it works.

In both examples you give in your question the sequence of execution is:

  1. Something requires the module named some_Name. (I don't think RequireJS is happy with module names that have spaces so I'm assuming a module name with an underscore.)

  2. RequireJS looks for the dependencies and the factory function for the module some_Name. The factory is the function given to define when you define the module.

    a. If it happens that define("some_Name"... was called before this step, then RequireJS just gets the dependencies and factory function that was given to define.

    b. If define("some_Name"... has not been executed yet, RequireJS will go to the network and attempt to fetch a file that contains the define call and execute it. By convention this will be a file with the same name as the module name + the .js extension, but this can be overridden in RequireJS' configuration.

  3. RequireJS checks whether the dependencies are loaded. If not, then it issues require calls for each dependency that is not loaded yet.

  4. RequireJS calls the factory function with the resolved dependencies.

Note that I did not go over all possible scenarios here. I'm sticking with the most common cases to keep things simple.

So...

Ok, I got that I can't directly use moduelOne.whatever because it is loaded asynchronous and it's not there if the callback is being called.

First Question, is this correct?

No, this is not correct. By the time moduleOne.whatEver(); executes, the module moduleOne must have been loaded already. If moduleOne is undefined this is not because of RequireJS' asynchronous nature but because there is a bug in how moduleOne is defined. For instance, if it exports the value undefined, then moduleOne will be undefined. Or you may get an undefined value for moduleOne.whatEver which will then cause an error when you try to call it, but this would be caused by, for instance, forgetting to export whatEver.

The difference between the 2nd case and the first is that the 2nd uses the CommonJS sugar syntax and this causes step 2 above to have a bit of additional processing. Before RequireJS executes the factory it parses the function (as you mentioned) and then processes the factory function as if the defined had been called like this:

define("some_Name", ['require', 'exports', './moduleOne'], function (require, exports) {

The require and exports modules are special modules defined internally by RequireJS. Note how RequireJS adds ./moduleOne at the end of the list of dependencies. Once this is done, the process is exactly the same as for the 1st case.

By the time var moduleOne = require("./moduleOne"); is executed, the module has already been loaded. So what this line does is merely return a reference to the module.