How requirejs load javascript async? - javascript

I am wondering anyone knows the internal of Requirejs, why it can load js asynchronourly? I know Javascript has no thread, how can async done by requirejs?

How RequireJS works?
Each module is contained inside a define call, which defines the module dependencies. With that, RequireJS makes a kind of tree to order each module from the one without dependencies, to the one with the most dependencies.
A module with only one dependency could be the one that depends on everything, if its dependency depends on another module, which depends on 2-3 other modules, and then it goes on like that.
define(['some/dep'], function(someDep){ /* module code */ });
In that order, RequireJS creates a <script> tag with the url to the module file and it inserts that script tag at the end of the <head>. The browser loads the JavaScript files and runs them in the order that they are present in the HTML.
Then, when every dependency is defined for the module to run, the function of that module is called with each dependency (previously defined) injected into the module factory function, and its result is stored.
How can it be async without threads?
It's async, but not necessarily parallel. Loading scripts can be parallel as the browser (at least chrome for sure) makes multiple connections to the server to fetch more files at once, but this has nothing to do with JS.
The async nature of JavaScript comes in an event-loop.
Each async callback is put in an event queue and when the synchronous call stack has completely finished executing, the next event callback from the queue is called.
It's easier to grasp when you see it, and you can in the chrome's dev tools Timeline tab.

Related

Dynamically loaded js, mutation observer and promises for nested js loading

I am working on a mechanism to dynamically load a set of js files that have some dependencies between them (e.g., my code after bootstrap after jquery). I defined a nested json type structure with the dependency relationships and then invoke a Promise based loadscript mechanism (thanks to some of the posts here) that makes async calls to load js files that are at the same level and invokes a recursive loadscript for js files that have dependencies between them.
The files are all correctly appended to HEAD in the order that i expect them to be. For the dependencies, i invoke loading a file for which there is a dependency in the onload handler of its predecessor. However, this does not seem to guarantee that the loaded js code is available to use (i.e., did not seem that the append had completed and the code been executed - e.g., var/const definitions were not available at the time of onload being invoked based on break points, etc... in debugger - i guess this seems correct).
So, added a mutationobserver that observed that the files were added to the DOM (e.g., childList change to HEAD). However, it appears that the mutation is invoked before the code is actually available for use.
Why do i think this? i put break points, console logs with timing info, etc.. at the point where the mutationObserver indicated that a change corresponding to the insertion of the newly loaded script had occurred (e.g., the observer firing because of the script added) but at that point, the code (e.g., some var definition) was not available in the globals in the debugger.
So, the question is not specific about my code but more about whether it is possible to know that the dynamically included js code has run and is available to use. For my own code i can handle this through other mechanisms but for third party js files i do not want to touch them.
So, more specifically, it does not seem that the actual appending of code to the DOM HEAD at the point detected by the mutationObserver actually means that the code has been executed and that it seems from other posts (e.g., Execution of dynamically loaded JS files or load and execute order of scripts ) that the actual execution of the code is somewhat asynchronous depending on what the browser is actually doing.
Any thoughts on the overall process understanding would be greatly appreciated.
Thanks,

What is the "order!" directive for in this requirejs/amd module?

I'm looking into what appears to be a case of javascript loading out of order in a legacy application. The application uses Require.js to load several modules, and one of our company's modules is executing prior to its dependencies being loaded.
My experience with Require.js and AMDs is very limited, and in researching I noted that in some areas dependencies are prefixed with an order! string, such as:
define(['order!jquery', ...
Whereas in other areas the prefix isn't used:
define(['jquery', ...
So far I can't find documentation of this directive. What's its effect?
Full information copied from here
Normally RequireJS loads and evaluates scripts in an undetermined
order. However, there are some traditional scripts that depend on
being loaded in a specific order. For those cases you can use the
order plugin. Download the plugin and put it in the same directory as
your app's main JS file. Example usage:
require(["order!one.js", "order!two.js", "order!three.js"], function () {
//This callback is called after the three scripts finish loading.
});
Scripts loaded by the order plugin will be fetched asynchronously, but
evaluated in the order they are passed to require, so it should still
perform better than using script tags in the head of an HTML document.
The order plugin is best used with traditional scripts. It is not
needed for scripts that use define() to define modules. It is possible
to mix and match "order!" dependencies with regular dependencies, but
only the "order!" ones will be evaluated in relative order to each
other.
Notes:
The order! plugin only works with JavaScript files that are cacheable by the browser. If the JS file has headers that do not
allow the browser to cache the file, then the order of scripts will
not be maintained.
Do not use the order! plugin to load other plugin-loaded resources. For instance. 'order!cs!my/coffescript/module' is not recommended.
You will get errors in some versions of IE and WebKit. This is due
to the workarounds the order plugin needs to do for those browsers
to ensureordered execution.

RequireJS: how to control the execution sequence of the paralleled loaded js script

i have no doubts on the parallel scripts loading step, but i would like to know how RequireJS control the execution sequence of the parallel loaded scripts.
example defined as below.
<script data-main="js/main.js" src="js/require.js"></script>
main.js:
define(['a', 'b'], function() {
window.alert("scheduler loaded!");
})
how to ensure that a.js is executed before b.js?
and when the main.js is fetched and parsed for dependencies, how to deal with it later to let it show up in dom as script element without another http fetch. when we add script element to dom, there is always a http fetch(no cache enabled case), isn't it?
Your main.js script actually does get loaded as a <script> tag and run first; it's just that the function inside of it will not run until a and b are loaded. You do not need to add any script tags yourself if you are using requirejs.
To ensure a's content function runs before b's, simply define a as a dependency inside of b
// b.js
define(['a'], function(a) {
// use a for initiation here
}
If you add 'c' to that array, then c will also become an indirect dependency of main.js.
EDIT: In response to comment, this might give a better understanding. Each numbered item is one single HTTP request.
HTML retrieved
Requirejs itself is the first script seen, so that is loaded first.
Requirejs sees that its tag has a data-main attribute, and so retrieves main.js as a <script> tag. Once main.js has loaded, it would simply run the function on the inside of it, BUT, it looks like this file has dependencies (the array) that have not been loaded yet. SO, it creates <script> tags simultaneously for...
a.js
and b.js. Now, let's say this one finishes loading first - maybe a.js is really big. BUT! It looks like b has a dependency - on A. So, it won't run the inside function just yet. Requirejs knows that it's already waiting for a.js's script tag, so it won't send out a separate request for it - it can just wait on it. Once that loads, a's function runs, then b's, then main's.
No HTTP requests are wasted here - Requirejs sends out requests as soon as it's aware of a dependency, and doesn't request individual scripts multiple times, except in rare occasions when it has no way of knowing that something is going to be loaded.
An example of this rare occasion might be if SmallWidget.js is an individual dependency, compiled into a large file called BundleOfWidgets.js. (For a final build, many scripts are often wrapped into one) If one script requests BundleOfWidgets.js but then another script requests SmallWidget.js before that arrives, it won't know it's actually loading SmallWidget.js in a big package, and so it will retrieve that individual file on its own.

Executing code before document.ready in requirejs

I see that require.js has support to execute code when document.ready() is fired. see: http://requirejs.org/docs/api.html#pageload
I was just wondering is there any way to get it to 100% execute code before document.ready() is invoked? For example, does the code main.js get executed before document.ready() event? Thanks.
There is no pure RequireJS solution to your request. In essence what you are asking for is:
I'd like a) to load my modules asynchronously but b) I want to load them synchronously.
Requirement a is entailed by the fact that you are using RequireJS. RequireJS is a loader designed to load AMD modules. AMD stands for asynchronous module definition. If you use RequireJS, you have to be okay with the fact that it operates asynchronously. So it cannot guarantee that any module will load and execute before the document is ready.
Requirement 'b' is entailed by your requirement that the code executes before the document is ready. This cannot be done otherwise than by forcing the execution of your modules to be synchronous. (I've given some thought about ways to delay the ready event but I don't see this as being generally possible. Solutions like jQuery.holdReady are not really delaying the event but only delaying those handlers that were set using jQuery.ready. The event still happens whenever the browser decides it happens but the handlers get fired later. And only the jQuery handlers are affected, nothing else.)
You can load your code using script elements (that don't use the async attribute) but then you won't be using RequireJS.
A solution that would give you something similar to RequireJS would be to use Almond. Your code would have to be built into a single bundle. And you could load this bundle synchronously. It would essentially have the same effect as using script elements but you would still benefit from modularization. Note that Almond comes with a series of limitations. You'll have to decide for yourself whether these limitations are a problem for you. I've explained how to use Almond synchronously in this answer.

Are Asynchronous Modules Always Asynchronous?

When multiple JavaScript modules are define()'d using AMD and concatenated into a single file, are those modules still considered asynchronous?
Generally speaking, just concatenating a bunch of AMD modules together won't make them synchronous. However, if you can live with additional limitations and select a loader that can do it, you can load AMD modules synchronously.
RequireJS
I don't know of a case where RequireJS will load anything synchronously, even if asynchronous loading is not needed. You could have the following in a <script> tag:
define("foo", [], function () {
});
require(["foo"], function (foo) {
});
There is nothing to load here because all the code is already present there. The foo module does not need to be fetched from anywhere. It's list of dependencies is known, etc. Yet, RequireJS will handle it asynchronously.
One source of confusion for some wondering about RequireJS' capability to load modules synchronously could be RequireJS' synchronous form of require. You can do:
define(function(require) {
var foo = require("foo");
});
The call to require here looks like it is synchronous but RequireJS transforms it behind the scenes into this, by adding "foo" to the list of define's required modules:
define(["foo"], function(require) {
var foo = require("foo");
});
So while the require call looks synchronous, RequireJS still handles it asynchronously.
Almond
Almond is a loader made by James Burke, who is also the author of RequireJS, that can load AMD modules synchronously. Now, Almond comes with a series of limitations. One such limitation is that you can't load anything dynamically. That is, the entire list of modules you want to load has to be part of the optimized bundle you create with r.js and give to almond for loading. If you can live with the limitations of almond, then it is quite possible to load a bunch of AMD modules synchronously. I've provided details on how to do this in this answer.
Yes, they are still considered async.
While the module itself doesn't have to be loaded from disk, the modules do need to be executed and there is a call back made.
Because you can combine SOME modules into a single file doesn't mean you have to combine all -- nor does RequireJS assume all there.
It will run what it can from your preload and async load the rest.

Categories