Javascript modular programming (three): the usage of require.js
The first and second parts of this series introduced the prototype and theoretical concepts of Javascript modules. Today, I will introduce how to use them in actual combat.
I use a very popular library require.js .
1. Why use require.js?
At the earliest, all Javascript code was written in one file, and it was enough to load this file. Later, with more and more codes, one file was not enough, it had to be divided into multiple files and loaded in sequence. I believe many people have seen the following webpage code.
<script src=”1.js”></script>
<script src=”2.js”></script>
<script src=”3.js”></script>
<script src=”4.js “></script>
<script src=”5.js”></script>
<script src=”6.js”></script>
This code loads multiple js files in sequence.
This way of writing has big disadvantages. First, when loading, the browser will stop rendering the web page. The more files loaded, the longer the web page will lose response time. Secondly, due to the dependency between js files, the loading order must be strictly guaranteed (such as the above example 1.js must be in front of 2.js), the module with the most dependency must be loaded last. When the dependency is very complicated, the writing and maintenance of the code will become difficult.
The birth of require.js is to solve these two problems:
![]()
(1) Realize the asynchronous loading of js files to prevent web pages from losing response;
(2) Manage dependencies between modules to facilitate code writing and maintenance.
Two, the loading of require.js
The first step in using require.js is to download the latest version from the official website .
After downloading, assuming it is placed under the js subdirectory, it can be loaded.
<script src=”js/require.js”></script>
Someone might think that loading this file may also cause the web page to become unresponsive. There are two solutions, one is to load it at the bottom of the page, and the other is to write it as follows:
<script src=”js/require.js” defer async=”true” ></script>
The async attribute indicates that the file needs to be loaded asynchronously to prevent the web page from losing its response. IE does not support this attribute, only defer is supported, so write defer as well.
After loading require.js, the next step is to load our own code. Assume that our own code file is main.js, which is also placed under the js directory. Then, just write as follows:
<script src=”js/require.js” data-main=”js/main” ></script>
The function of the data-main attribute is to specify the main module of the webpage program. In the above example, it is main.js under the js directory. This file will be loaded by require.js first. Since the default file extension of require.js is js, main.js can be abbreviated as main.
Three, the writing of the main module
The main.js in the previous section, I called it the “main module”, which means the entry code of the entire web page. It is a bit like the main() function of the C language, and all the code runs from here.
Let’s take a look at how to write main.js.
If our code does not depend on any other modules, we can write javascript code directly.
// main.js
alert(“Loading successfully!”);
But in this case, there is no need to use require.js. The really common situation is that the main module depends on other modules, and then the require() function defined by the AMD specification is used.
// main.js
require([‘moduleA’,’moduleB’,’moduleC’], function (moduleA, moduleB, moduleC){
// some code here
});
The require() function accepts two parameters. The first parameter is an array, indicating the modules it depends on. The above example is [‘moduleA’,’moduleB’,’moduleC’], that is, the main module depends on these three modules; the second parameter is a callback function, the current After the specified modules are loaded successfully, it will be called. The loaded modules will be passed into the function as parameters, so that these modules can be used inside the callback function.
require() loads moduleA, moduleB, and moduleC asynchronously, the browser will not lose response; the callback function it specifies will only run after the previous modules are loaded successfully, which solves the dependency problem.
Below, we look at a practical example.
Assuming that the main module depends on the three modules of jquery, underscore and backbone, main.js can be written like this:
require([‘jquery’,’underscore’,’backbone’], function ($, _, Backbone){
// some code here
});
require.js will load jQuery, underscore and backbone first, and then run the callback function. The code of the main module is written in the callback function.
Fourth, the loading of the module
In the last example of the previous section, the dependent modules of the main module are [‘jquery’,’underscore’,’backbone’]. By default, require.js assumes that these three modules are in the same directory as main.js, the file names are jquery.js, underscore.js and backbone.js, and then automatically loaded.
Using the require.config() method, we can customize the loading behavior of the module. require.config() is written at the head of the main module (main.js). The parameter is an object, and the paths attribute of this object specifies the loading path of each module.
require.config({
paths: {
“jquery”: “jquery.min”,
“underscore”: “underscore.min”,
“backbone”: “backbone.min”}
});
The above code gives the file names of the three modules, and the path defaults to the same directory (js subdirectory) as main.js. If these modules are in other directories, such as the js/lib directory, there are two ways to write them. One is to specify the paths one by one.
require.config({
paths: {
“jquery”: ” lib/ jquery.min”,
“underscore”:” lib/ underscore.min”,
“backbone”: ” lib/ backbone.min”}
});
The other is to directly change the base directory (baseUrl).
require.config({
baseUrl: “js/lib”,
paths: {
“jquery”: “jquery.min”,
“underscore”: “underscore.min”,
“backbone”: “backbone.min”}
});
If a module is on another host, you can also specify its URL directly, such as:
require.config({
paths: {
“jquery”: “https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min”
}
});
require.js requires that each module is a separate js file. In this case, if multiple modules are loaded, multiple HTTP requests will be issued, which will affect the loading speed of the web page. Therefore, require.js provides an optimization tool . After the module is deployed, you can use this tool to merge multiple modules into one file to reduce the number of HTTP requests.
Five, the writing of the AMD module
The modules loaded by require.js use AMD specifications. In other words, the module must be written in accordance with AMD’s regulations.
Specifically, the module must be defined with a specific define() function. If a module does not depend on other modules, it can be directly defined in the define() function.
Suppose there is a math.js file, which defines a math module. Then, math.js will write like this:
// math.js
define(function (){
var add = function (x,y){
return x+y;
};
return {
add: add
};});
The loading method is as follows:
// main.js
require([‘math’], function (math){
alert(math.add(1,1));
});
If this module also depends on other modules, then the first parameter of the define() function must be an array indicating the dependency of the module.
define([‘myLib’], function(myLib){
function foo(){
myLib.doSomething();
}
return {
foo: foo
};
});
When the require() function loads the above module, the myLib.js file will be loaded first.
Six, load non-standard modules
Theoretically, the module loaded by require.js must be a module defined with the define() function in accordance with the AMD specification. But in fact, although some popular function libraries (such as jQuery) already comply with AMD specifications, more libraries do not. So, can require.js load non-standard modules?
The answer is yes.
Before such modules are loaded with require(), they must first use require.config() to define some of their characteristics.
For example, the two libraries underscore and backbone are not written in AMD specifications. If you want to load them, you must first define their characteristics.
require.config({
shim: {
‘underscore’:{
exports:’_’
},‘backbone’: {
deps: [‘underscore’,’jquery’],
exports:’Backbone’
}}
});
require.config() accepts a configuration object. In addition to the paths attribute mentioned above, this object also has a shim attribute to configure incompatible modules. Specifically, each module should define (1) exports value (output variable name), indicating the name of this module when it is called externally; (2) deps array, indicating the dependency of the module.
For example, the jQuery plug-in can be defined like this:
shim: {
‘jquery.scroll’: {
deps: [‘jquery’],
exports:’jQuery.fn.scroll’
}
}
Seven, require.js plugin
require.js also provides a series of plug-ins to achieve some specific functions.
The domready plugin allows the callback function to run after the page DOM structure is loaded.
require([‘domready!’], function (doc){
// called once the DOM is ready
});
The text and image plugins allow require.js to load text and image files.
define([
‘text!review.txt’,
‘image!cat.jpg’
],
function(review,cat){console.log(review);
document.body.appendChild(cat);
}
);
Similar plugins include json and mdown, which are used to load json files and markdown files.
(over)