requirejs - Performance of multiple calls to require - javascript

I'm wondering what is the proper approach for using RequireJS in a project with multiple modules, regarding performance of multiple require calls with less dependencies vs a single require with all the dependencies.
Let's take the case where, for an app, I need to load some modules: gmaps, jquery, module1, module2, module3. The use for some of the modules is quite independent. So, the question is which of the following alternatives is recommended (supposedly this code is the main module loaded into the page):
require(['gmaps'], function(gmaps){
gmaps.use();
});
require(['jquery','module1'], function(jquery, module1){
module1.use();
});
require(['jquery','module2'], function(jquery, module2){
module2.use();
});
require(['jquery','module3'], function(jquery, module3){
module3.use();
});
vs
require(['jquery','module1','module1','module1','gmaps'], function(jquery, module1,module2,module3,gmaps){
module1.use();
module2.use();
module3.use();
gmaps.use();
});
In other words, what is the performance penalty of require and which is the best practice.

The answer to the question here is "it depends." I'm speaking as someone who has used RequireJS in a large application but who has not thoroughly read the code of RequireJS. (Just pointing out that people who know the innards of RequireJS inside and out might explain differently than I do.) The cost of require can be broken down into 3 cost scenarios:
If the module has never been loaded, require loads a file from a server, executes the file, executes the factory function for the module and returns a reference to the module. (The cost of loading files from the network usually dwarfs other costs.)
If the module has already been loaded but never required, require executes the factory function for the module and returns a reference to the module. (This will normally happen in an optimized application.)
If the module has already been loaded and required, require returns a reference to the module.
Cost scenario 1 > cost scenario 2 > cost scenario 3.
First, let's consider the case where there is one module per file. The application is not optimized. I have a module named module1 which is required once in a blue moon. It's usage in a main application could be modeled like this:
define(["module1", <bunch of other required modules>],
function (module1, <bunch of other modules variables>) {
[...]
if (rare_condition_happening_once_in_a_blue_moon)
module1.use();
[...]
});
Here I always pay the price of cost scenario number 1 even if I don't use the module. It would be better to do:
define([<bunch of required modules>],
function (<bunch of module variables>) {
[...]
if (rare_condition_happening_once_in_a_blue_moon)
require(["module1"], function (module1) {
module1.use();
});
[...]
});
This way, I'd pay the price of loading the module only once in a blue moon.
Now, what if I need to use module repeatedly? This can be modeled as:
define(["module1", <bunch of other required modules>],
function (module1, <bunch of other modules variables>) {
[...]
for(iterate a gazillion times)
module1.use();
[...]
});
In this case, cost scenario number 1 is paid once, and that's all. If I use require like this:
define([<bunch of required modules>],
function (<bunch of module variables>) {
[...]
for(iterate a gazillion times)
require(["module1"], function (module1) {
module1.use();
});
[...]
});
I'm paying cost scenario number 1 once and a (gazillion times - 1) cost scenario number 3. At the end of the day, whether the module1 should be included among the requirements of the define call or in a separate require call depends on the specifics of your application.
The analysis changes if the application has been optimized by using r.js or a home-made optimization. If the application is optimized so that all modules are in one file, every time you paid cost scenario 1 in the cases above, you'd pay cost scenario 2 instead.
For the sake of completeness, I'll add that in cases where you do not know ahead of time the module you might want to load, using require is necessary.
define([<bunch of other required modules>],
function (<bunch of other modules variables>) {
[...]
require(<requirements unknown ahead of time>, function(m1, m2, ...) {
m1.foo();
m2.foo();
[...]
});
[...]
});

It depends on what loading behavior you want.
When you require a module that has not been required yet, a HTTP request will be made to load the required module. If the required module has been loaded atleast once, it is stored in require's cache, and so when you require the module the second time, it will use the cached value.
So, its a choice between lazy or eager loading.
The problem that require is trying to solve, is that each module can define it's dependencies - so your first approach would probably be "best practice". In the end, you'd want to use r.js to build your application into a single JS file.

Second approach is in my opinion against the main purpose of the require js, which is the separation of different program logic. Why would you use requirejs if you put your code in the one "module" anyway? .In terms of performance it is important to define what is your definition of performance. If it is the speed of your code execution, then there should be no visible difference. The code will execute as soon as all required modules are loaded. If on the other hand, what you mean by performance is: when the code execution starts - then obviously in the second approach you will have additional overhead caused by additional requests for files where your required code is located.
EDIT:
After taking a closer look to the question, the first part of my answer did not fit it well. The code is actually referencing external modules, so the second option is not against the purpose of the requirejs library and is actually the better approach as long as the module which combines its dependencies is not trying to do too much.

Related

How does es6 module loading work

I've been reading about es6 module loaders and I just don't quite understand how it works and am hoping someone can enlighten me.
In the practical workflows link above they have an example like this
System.import('app/app').then(function(app) {
// app is now the Module object with exports as getters
});
No problem with that - I get it. But then I see stuff like this
var $ = require('jquery');
and get really confused. What happens if at the time of this call jquery has not yet been transferred to the browser? Does the thread just spin? Does the browser parse your script behind-the-scenes and reform it into a callback like RequireJs does? Is what it does configurable? Are there specific limitations?
Can someone give me a rundown?
The ES6 Module Loader will fetch the source, determine dependencies, and wait until those dependencies have loaded before executing the module. So by the time the require executes, the dependency is already sitting there waiting to be executed.
When loading CommonJS through an ES6 module loader, we rely on statically parsing out the require statements from the source, and only executing the source once those requires have loaded.
In this way we can support CommonJS in the browser loaded dynamically. Circular references are treated identically to the way they are handled in Node.
The regular expressions parsing out the require are actually pretty reliable and quick, while taking into account comments and surrounding tokens. See https://github.com/systemjs/systemjs/blob/master/lib/extension-cjs.js#L10 for the one used by SystemJS.
There is one remaining limitation with this approach and that is dynamic and conditional CommonJS requires like if (condition) require('some' + 'name') aren't detected properly. This is a necessary cost though to make CommonJS behave as a fully asynchronous module format in the browser.

RequireJS - Loading AMD modules both inside a require flow and inline

Consider this:
<script src='global.js'></script>
<script src='require.js'></script>
<script>
require(['modular_foo'], function() {
//do stuff
});
...and in side global.js we have, among other things:
//global.js
$.getScript("modular_bar.js");
where both modular_foo and modular_bar are anonymously defined AMD modules. Using requireJS, loading something like the above would give you our favourite error, mismatched anonymous define() modules.
It's fine enough as to why that error occurs (read up on that page if you'd like to know), but the problem is, what if you can't get out of this situation?
I'm working in an established platform which is very gradually migrating to a RJS flow, for now there's no way out of using both inline legacy scripts (some of which have AMD checks to trigger define()) and our requireJS entry-point simultaneously.
In some cases I can simply place inline AMD-compatible scripts above loading the require.js library, but that doesn't work when you need to load other things (modular_bar.js) asynchronously depending on the DOM content. I could also just comment out all AMD checks from those files loading externally to RJS but that's preventing making them incompatible with ever being loaded in a modular flow.
Anyone out there had a similar experience? How do you blend your flows to overcome these sorts of conflicts?
I do not have experience using this solution in a production environment but I spent a couple days on this question figuring out the best way to approach it.
You can use a modified RequireJS library that does not allow the anonymous define's to execute, if it is being passed through eval. Also, you can disallow any define calls by removing type check for string on name in the snippet below.
The following snippet is a modification to RequireJS that will ignore anonymous defines if being called by eval. You can find the fully modified require.js in this GitHub Gist.
The code relies on the parse-stack library. If you can't include the library before RequireJS, I suggest just concatenating it to the top of of the file.
Demo
// This is a snippet of RequireJS
// ...
define = function (name, deps, callback) {
var node, context;
// We will allow named modules to be defined by `eval`
if (!(typeof name == 'string' || name instanceof String))
{
var stack = parseStack(new Error());
// If we find any eval in the stack, do not define the module
// This is to avoid the "Mismatched anonymous define() module" error
// Caused by executing an anonymous define without requireJS
for(var i = 0; i < stack.length; i++)
{
if(stack[i].name == "eval")
{
return;
}
}
}
// ...

RequireJS: Difference between "requirejs" and "require" functions

I am using requireJS 2.x. I found out that some tutorials (and the official docs) sometimes use
requirejs.config({ [...] });
requirejs(["module"]) ...
and sometimes
require.config({ [...] });
require(["module"]) ...
Is there any difference between those two functions (require and requirejs)? I could not find any word about that in the docs. :(
They are exactly the same.
The reason is some environments might already have a require, in which case RequireJS doesn't overwrite it and allows usage of the library through requirejs
See this commit - https://github.com/jrburke/requirejs/commit/be45948433b053921dc6a6a57bf06d04e13b3b39
Are requirejs And require the Same?
As of RequireJS 2.1.15, require and requirejs in the global space are indeed "exactly the same", as can be evidenced by this test you can perform in the console:
> require === requirejs
true
That the test returns true tells you they are the exact same function object. They are not two functions that happen to have similar or identical code. They are the same object, period.
Note, however when you execute define(['require'], function (require) { The require passed to the function is normally different from the global require.
Should You Use require or requirejs?
It depends. RequireJS is an AMD loader but it is not the only loader in town. If you want to write code that conforms 100% to the AMD spec, so that someone using your code can use whatever loader they want without having to modify your code, then you should use require at the global level, because requirejs is specific to RequireJS. Another AMD loader won't define it. The AMD spec defines require but not requirejs.
If you are loading something else that defines a global require then you have to use requirejs at the global level to avoid conflict.
Inside a module, always use define to obtain a reference to require. You should do this quite irrespective of whether there is a conflict in the global space.
OK, they may indeed be "exactly the same". Let's then focus on why you would use one versus the other...
What is unclear is what should be considered "best practice": If requirejs provides extra assurance "if some environments might already have a require", then wouldn't it be a good idea to always use the requirejs function to define a require configuration rather than the require function?
Also, what happens if the unthinkable happens and the environment in question not only already has a "require" defined but also has a "requirejs" defined? Does that mean we should have a requirejsjs too? And so on...?
They are Same
Open website which loaded require already
then open Chrome console
type require in console and press enter
type requirejs in console and press enter
you can find that they are same function with different names

Why do concatenated RequireJS AMD modules need a loader?

We love RequireJS and AMD during development, where we can edit a module, hit reload in our browser, and immediately see the result. But when it comes time to concatenate our modules into a single file for production deployment, there apparently has to be an AMD loader still present, whether that loader is RequireJS itself or its smaller partner “almond” as explained here:
http://requirejs.org/docs/faq-optimization.html#wrap
My confusion is: why is a loader necessary at all? Unless you have very unusual circumstances that make it necessary for you to make require() calls inside of your modules, it would appear that a series of AMD modules could be concatenated without a loader present at all. The simplest possible example would be a pair of modules like the following.
ModA.js:
define([], function() {
return {a: 1};
});
ModB.js:
define(['ModA'], function(A) {
return {b : 2};
});
Given these two modules, it seems that a concatenator could simply produce the following text, and not burden the production server or browser with the extra bandwidth or computation required by either RequireJS or Almond.
I imagine a concatenator that produces (and I am using chevron-quotes «,» to show where the snippets from the two modules above have been inserted):
(function() {
var ModA = «function() {
return {a: 1};
}»();
var ModB = «function(A) {
return {b : 2};
}»(ModA);
return ModB;
})();
This, so far as I can see, would correctly reproduce the semantics of AMD, with a minimum of extraneous glue JavaScript. Is there such a concatenator available? If not, would I be a fool for thinking that I should write one — are there really very few code bases that consist of simple and clean modules written with define() and that never need further require() calls inside that kick off later asynchronous fetches of code?
An AMD optimiser has the scope to optimise more than the number of files to be downloaded, it can also optimise the number of modules loaded in memory.
For example, if you have 10 modules and can optimise them to 1 file, then you have saved yourself 9 downloads.
If Page1 uses all 10 modules then that's great. But what if Page2 only uses 1? An AMD loader can delay the execution of the 'factory function' until a module is require'd. Therefore, Page2 only triggers a single 'factory function' to execute.
If each module consumes 100kb of memory upon being require'd, then an AMD framework that has runtime optimisation will also save us 900kb of memory on Page2.
An example of this could be an 'About Box' style dialog. Where the very execution of it is delayed until the very last second as it won't be accessed in 99% of cases. E.g. (in loose jQuery syntax):
aboutBoxBtn.click(function () {
require(['aboutBox'], function (aboutBox) {
aboutBox.show();
}
});
You save the expense of creating the JS objects and DOM associated with the 'About Box' until you are sure it's necessary.
For more info, see Delay executing defines until first require for requirejs's take on this.
The only real benefit is if you use modules across sections so there's a benefit to caching modules independently.
I had the same need, so I created a simple AMD "compiler" for that purpose that does just that. You can get it at https://github.com/amitayh/amd-compiler
Please note that it has many features missing, but it does the job (at least for me). Feel free to contribute to the codebase.
In case you compile you code with require.js into a single large file for production, you can use almond.js to completely replace require.
Almond only handles the module references management not the loading itself which is no longer needed.
Be careful of the restrictions almond imposes in order to work
There is no reason why there couldn't be a build tool such as the one you propose.
The last time* I looked at the optimizer's output, it converted the modules to explicitly named modules, and then concatenated those together. It relied on require itself to make sure that the factory functions were called in the right order, and that the proper module objects were passed around. To build a tool like you want, you would have to explicitly linearize the modules -- not impossible, but a lot more work. That's probably why it hasn't been done.
I believe** that the optimizer has a feature to automatically include require itself (or almond) into the built file, so that you only have to have one download. That would be larger than the output of the build tool you want, but otherwise the same.
If there was a build tool that produced the kind of output you're asking for, It would have to be more careful, in case of the synchronous require, the use of exports instead of return, and any other CommonJS compatibility features.
*That was a few years ago. 2010, I think.
**But can't seem to find it right now.

Curl throwing ‘Promise already completed’ error

I’m currently testing various asynchronous-resource-loaders to see which one I want to use. At the moment Curl is throwing a ‘Promise already completed’ error…and their documentation says ‘this should never happen’.
I “suspect” I must to use a ‘define’ within each file being loaded (hope not). Further, their documentation says Curl can work with non-AMD javascript files. But...I am new to AMD and since Curl is far-faster than the other ones I'm testing...I am willing to put some time into understanding this better.
Lastly...
Even though FireBug shows the errors...all the files STILL LOAD asynchronously! But, BECAUSE there are errors...the 'then' portion of the code never gets called.
So My Questions Are:
Do I have to update all the JavaScript file-objects to be contained in a 'define'? (...hope not)
Can you see any other problem syntactically?
The Head’s Code Looks Like This:
<script type="text/javascript">
///<summary>Configuration</summary>
curl = { baseUrl: 'Includes/JavaScript/' };
</script>
<script src="Loaders/Curl/curl.js" type="text/javascript"></script>
<script type="text/javascript">
function onSuccess() {
}
function onError(ex) {
//alert(ex);
}
require(["MooTools/Core/mootools-1.2.2-core-jm",
"MooTools/mGeneral",
"jQuery/Core/jquery-1.3.2",
"jQuery/Core/jquery.tools.min",
"jQuery/ThirdPartyPlugIns/jquery.tmpl"])
.then(onSuccess, onError);
//require(["jQuery/TopUp/top_up-min"], null);
require(["jQuery/ThirdPartyPlugIns/jquery.dimensions",
"jQuery/ThirdPartyPlugIns/jQuery.Color.Animations",
"jQuery/ThirdPartyPlugIns/jquery.corners.min",
"jQuery/ThirdPartyPlugIns/jquery.tipsy",
"jQuery/ThirdPartyPlugIns/jquery.numberformatter-1.1.0",
"jQuery/ThirdPartyPlugIns/jquery.tipsy"]);
require(["general",
"WindowCenter",
"ThirdPartyPlugin/KeyBoardCapture",
"ThirdPartyPlugin/bsn.AutoSuggest_2.1.3",
"ee/8Ball",
"ee/EE"]);
</script>
Again...I'm sure it is caused by inexperience with AMD-styled code, but I still need help...so any is appreciated.
Typically, you should wrap your modules in a define() or append a define() at the end of the file if those modules have no dependencies. It seems, though, that those modules all depend on jQuery, if not other modules/files.
Since you're not using standard AMD require()/define() protocol, AMD is not really helping you with these modules. Unless you plan to write your own modules using define(), then you could use just about any async loader.
That said, there is a way to make curl.js work with non-AMD modules/files. Use the js! plugin. Here's your first block of files translated to use the js! plugin (note I also added the ".js" ext back on which I like to do with non-modules):
// we load the core files first, then get the next block that depends on them
curl([
"js!MooTools/Core/mootools-1.2.2-core-jm.js",
"js!jQuery/Core/jquery-1.3.2.js"
]).next([
"js!MooTools/mGeneral.js",
"js!jQuery/Core/jquery.tools.min.js",
"js!jQuery/ThirdPartyPlugIns/jquery.tmpl.js"
]).then(onSuccess, onError);
If any of those files within each array depend on each other, you can also use the !order suffix on them to ensure they wait for other files before executing/evaluating (be sure you're setting proper cache headers, though). Actually, the !order suffix is the fastest method as long as there are no caching issues (mobile browsers add some additional constraints on file size).
Were there any other error messages? Specifically, I would expect curl.js to throw at least one error besides just "Promise not completed".
Also, please check the Net tab (Firebug) or the Network tab (Chrome) to check that curl.js is looking in the correct location for the modules.
FWIW, I am planning to remove the alias require --> curl. The reason is that the global require function is non-standard (and explicitly not standardized in the AMD proposal). I suggest you use curl() instead of require().
curl.js also allows it's top-level api to be aliased explicitly via the "apiName" config param if you really, really want to use the name "require". :)
<script>curl = { apiName: "require" }; </script>
<script src="path/to/curl.js"></script>
<script>require(["some/modules"]).then(success, failure);</script>
More FWIW: the standard require is typically only needed in a module and can be requested by including it as a dependency:
define(["require"], function (require) {
require(["another/module"], function (another) {
// use another module here
});
});
-- John
If you're only doing normal javascript file loading (not modules), as it appears, i would encourage you to check out LABjs (http://labjs.com). LABjs focuses on being the most performance optimized loading solution (to the exclusion of some other features like module/dependency style stuff).
In fact, LABjs 2.0a (https://github.com/getify/LABjs/blob/master/next/LAB.src.js), which will be fully released in the next few days, is really exceptionally fast (even more than 1.2) at loading general scripts in parallel. I encourage you to give it a try, unless (as John eludes to above) you plan to go to module syntax... then stick with Curl or RequireJS.

Categories