Let’s put our revealing module pattern into asynchronous modules definition (AMD).
Asynchronous module definition (AMD) is a JavaScript API for defining modules such that the module and its dependencies can be asynchronously loaded. It is useful in improving the performance of websites by bypassing synchronous loading of modules along with the rest of the site content.
modular, we generally mean it’s composed of a set of highly decoupled, distinct pieces of functionality stored in modules. As you probably know, loose coupling facilitates easier maintainability of apps by removing dependencies where possible.
Loose coupling implies each component can operate or be tested independently of other components.
Tight coupling implies each component “knows” the details or inner workings of other components.
In just a few lines of code you can provide for architectural features above to improve from revealing module pattern to asynchornous module definition code. Here’s a look into why and how.
Script Tag Vomit
James Burke of Mozilla Messaging who writes require.js explains the problem in his presentation Fast, modular code with jQuery and RequireJS.
It’s slow with many http requests, manual dependencies (did I load it in the right order?), and a real lack of encapsulation.
Asynchronous Module Definition is designed to solve this issue.
Script Loaders
There are a number of great loaders for handling module loading in the AMD and CJS formats. My personal preference us RequireJS. There is also curl.js.
Complete tutorials on these tools are outside the scope of this article, but I can recommend reading John Hann’s post about curl.js and James Burke’s RequireJS API documentation for more.
RequireJS
Is an asynchornous script tag loader that you can call at any time. It provides encapsulation, traces nested dependencies, and provides an optimization tool.
You end up with the following code in your page:
<script src="../js/require-jquery.js"></script> <script>require(["app"]);</script>
You also can get optimized CSS files.
Modules
Modules provide strict encapsulation and isolation of the globals, as you learned in Namespaces, Anonymous Module, Revealing Module Pattern. For example, you can have multiple version of a module on a page. So if one part of your script requires one version of JQuery and another script requires another version, you are still in business.
Let’s take an example of taking jQuery and making an extension with and without use code written using the asynchronous module pattern.
Module pattern
The module pattern looks like this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function($) { | |
//Extend jQuery | |
$.fn.foo = function() {}; | |
$(function() { | |
//execute on | |
//page load | |
}); | |
}(jQuery)); |
Asynchronous Module Pattern
The RequireJS Pattern looks like this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require([“jquery”], function($) { | |
//Extend jQuery | |
$.fn.foo = function() {}; | |
$(function() { | |
//execute on | |
//page load | |
}); | |
}); |
There is a quite a bit of difference between the two examples. In one, you are calling the function and relying that you have already loaded jQuery. In the Asynchronous Module, you require it to be loaded before loading or running your module.
It’s About Dependencies
With Asynchronous Module Definition, you can specify the dependencies for each module, and those dependencies are automatically loaded for you.
Even if you are using ASP.NET Bundling and Minification, you and your team must put the order loading into the C# code. Instead, if you use RequireJS, even if the order is slightly out of whack in the server code, when you use RequireJS define()
and require()
will end up with your code working as expected.
Why Not Web Workers?
Web Workers might be another way to load scripts, but it is a message-passing API, and the scripts likely want to interact with the DOM, so it means just using the worker to fetch the script text, but pass the text back to the main window then use eval/script with text body to execute the script.
Coming up
In the following posts, you will learn how to use RequireJS to build your modules in Getting Started with Modules Using RequireJS.
Sample code is available in the DevDays GitHub repository. See https://github.com/devdays/object-javascript
Resources
JavaScript Design Patterns: Mediator