理解用requireJs 来实现javascript的模块化加载
这是我看到的一片关于requirejs的初学者的文章,写的不错,下面结合自己的理解记录一下:
原文:http://www.sitepoint.com/understanding-requirejs-for-effective-javascript-module-loading/
Modular programming is used to break large applications into smaller blocks of manageable code. Module based coding eases the effort for maintenance and increases reusability. However, managing dependencies between modules is a major concern developers face throughout the application development process. RequireJS is one of the most popular frameworks around for managing dependencies between modules. This tutorial examines the need for modularized code, and shows how RequireJS can help.
Loading JavaScript Files
Large applications often require a number of JavaScript files. Generally, they are loaded one by one using<script>
tags. Additionally, each file can potentially be dependent on other files. The most common example would be jQuery plugins, which are all dependent upon the core jQuery library. Therefore, jQuery must be loaded before any of its plugins. Let’s look at a simple example of JavaScript file loading in real applications. Assume we have the following three JavaScript files.
purchase.js
function purchaseProduct(){
console.log("Function : purchaseProduct"); var credits = getCredits();
if(credits > 0){
reserveProduct();
return true;
}
return false;
}
products.js
function reserveProduct(){
console.log("Function : reserveProduct"); return true;
}
credits.js
function getCredits(){
console.log("Function : getCredits"); var credits = "100";
return credits;
}
In this example, we are trying to purchase a product. First, it checks whether enough credits are available to purchase the product. Then, upon credit validation, it reserves the product. Another script, main.js
, initializes the code by calling purchaseProduct()
, as shown below.
var result = purchaseProduct();
What Can Go Wrong?
In this example, purchase.js
depends upon both credits.js
and products.js
. Therefore, those files need to be loaded before calling purchaseProduct()
. So, what would happen if we included our JavaScript files in the following order?
<script src="products.js"></script>
<script src="purchase.js"></script>
<script src="main.js"></script>
<script src="credits.js"></script>
Here, initialization is done before credits.js
is loaded. This will result in the error shown below. And this example only requires three JavaScript files. In a much larger project, things can easily get out of control. That’s where RequireJS comes into the picture.
Introduction to RequireJS
RequireJS is a well known JavaScript module and file loader which is supported in the latest versions of popular browsers. In RequireJS we separate code into modules which each handle a single responsibility. Additionally, dependencies need to be configured when loading files. Let’s get started by downloadingRequireJS. Once downloaded, copy the file to your project folder. Let’s assume our project’s directory structure now resembles the following image.
All the JavaScript files, including the RequireJS file, are located inside the scripts
folder. The filemain.js
is used for initialization, and the other files contain application logic. Let’s see how the scripts are included inside the HTML file.
<script data-main="scripts/main" src="scripts/require.js"></script>
This is the only code required to include files using RequireJS. You might be wondering what happened to the other files and how they are included. The data-main
attribute defines the initialization point of the application. In this case, it is main.js
. RequireJS uses main.js
to look for other scripts and dependencies. In this scenario all the files are located in same folder. Using logic, you can move the files to any folder you prefer. Now, let’s take a look at main.js
.
require(["purchase"],function(purchase){
purchase.purchaseProduct();
});
In RequireJS, all code is wrapped in require()
or define()
functions. The first parameter of these functions specifies dependencies. In the previous example, initialization is dependent on purchase.js
, since it defines purchaseProduct()
. Note that the file extension has been omitted. This is because RequireJS only considers .js
files.
The second parameter to require()
is an anonymous function which takes an object that is used to call the functions inside the dependent file. In this scenario, we have just one dependency. Multiple dependencies can be loaded using the following syntax.
require(["a","b","c"],function(a,b,c){
});
Creating Applications with RequireJS
In this section we are going to convert the plain JavaScript example discussed in the previous section into RequireJS. We already covered main.js
, so let’s move on to the other files.
purchase.js
define(["credits","products"], function(credits,products) { console.log("Function : purchaseProduct"); return {
purchaseProduct: function() { var credit = credits.getCredits();
if(credit > 0){
products.reserveProduct();
return true;
}
return false;
}
}
});
First, we declare that purchase functionality depends on credits and products. Inside the return
statement, we can define the functions of each module. Here, we have called the getCredits()
andreserveProduct()
functions on the objects passed. product.js
and credits.js
are similar, and are shown below.
products.js
define(function(products) {
return {
reserveProduct: function() {
console.log("Function : reserveProduct"); return true;
}
}
});
credits.js
define(function() {
console.log("Function : getCredits"); return {
getCredits: function() {
var credits = "100";
return credits;
}
}
});
Both of these files are configured as independent modules – meaning they are not dependent on anything. The important thing to notice is the use of define()
instead of require()
. Choosing betweenrequire()
or define()
depends on the structure of your code, and will be discussed in the following section.
Using require()
vs. define()
Earlier I mentioned that we can use both require()
and define()
to load dependencies. Understanding the difference between those two functions is essential to managing dependencies. The require()
function is used to run immediate functionalities, while define()
is used to define modules for use in multiple locations. In our example we need to run the purchaseProduct()
function immediately. So, require()
was used inside main.js
. However, the other files are reusable modules and therefore use define()
.
Why RequireJS is Important
In the plain JavaScript example, an error was generated due to the incorrect order of file loading. Now, delete the credits.js
file in the RequireJS example and see how it works. The following image shows the output of the browser inspection tool.
The difference here is that no code has been executed in the RequireJS example. We can confirm it since nothing is printed on the console. In the plain JavaScript example we had some output printed on the console before generating the error. RequireJS waits until all the dependent modules are loaded before executing the functionality. If any modules are missing, it doesn’t execute any code. This helps us maintain the consistency of our data.
Managing the Order of Dependent Files
RequireJS uses Asynchronous Module Loading (AMD) for loading files. Each dependent module will start loading through asynchronous requests in the given order. Even though the file order is considered, we cannot guarantee that the first file is loaded before the second file due to the asynchronous nature. So, RequireJS allows us to use the shim
config to define the sequence of files which need to be loaded in correct order. Let’s see how we can create configuration options in RequireJS.
requirejs.config({
shim: {
'source1': ['dependency1','dependency2'],
'source2': ['source1']
}
});
RequireJS allows us to provide configuration options using the config()
function. It accepts a parameter called shim
which we can use to define the mandatory sequences of dependencies. You can find the complete configuration guide in the RequireJS API documentation.
define(["dependency1","dependency2","source1","source2"], function() { );
Under normal circumstances these four files will start loading in the given order. Here, source2
depends onsource1
. So, once source1
has finished loading, source2
will think that all the dependencies are loaded. However, dependency1
and dependency2
may still be loading. Using the shim config, it is mandatory to load the dependencies before source1
. Hence, errors will not be generated.
Conclusion
I hope this tutorial helps you get started with RequireJS. Although it seems simple, it is really powerful in managing dependencies in large scale JavaScript applications. This tutorial alone is not enough to cover all the aspects of RequireJs, so I hope you learn all the advanced configurations and techniques using the official website.
And if you enjoyed reading this post, you’ll love Learnable; the place to learn fresh skills and techniques from the masters. Members get instant access to all of SitePoint’s ebooks and interactive online courses, likeSimply JavaScript.
Comments on this article are closed. Have a question about JavaScript? Why not ask it on our forums?
理解用requireJs 来实现javascript的模块化加载的更多相关文章
- 该如何理解AMD ,CMD,CommonJS规范--javascript模块化加载学习总结
是一篇关于javascript模块化AMD,CMD,CommonJS的学习总结,作为记录也给同样对三种方式有疑问的童鞋们,有不对或者偏差之处,望各位大神指出,不胜感激. 本篇默认读者大概知道requi ...
- RequireJS与SeaJS模块化加载示例
web应用越变的庞大,模块化越显得重要,尤其Nodejs的流行,Javascript不限用于浏览器,还用于后台或其他场景时,没有Class,没有 Package的Javascript语言变得难以管理, ...
- RequireJS 模块化加载框架使用
RequireJS 是一个遵循 AMD 规范的模块化加载框架 与上文seajs一样,这里简单介绍其相关用法 同样的,首先是下载好 require.js --> http://requirejs. ...
- 【 js 模块加载 】深入学习模块化加载(node.js 模块源码)
一.模块规范 说到模块化加载,就不得先说一说模块规范.模块规范是用来约束每个模块,让其必须按照一定的格式编写.AMD,CMD,CommonJS 是目前最常用的三种模块化书写规范. 1.AMD(Asy ...
- 再唠叨JS模块化加载之CommonJS、AMD、CMD、ES6
Javascript模块化编程,已经成为一个迫切的需求.理想情况下,开发者只需要实现核心的业务逻辑,其他都可以加载别人已经写好的模块. Javascript社区做了很多努力,在现有的运行环境中,实现” ...
- 【 js 模块加载 】【源码学习】深入学习模块化加载(node.js 模块源码)
文章提纲: 第一部分:介绍模块规范及之间区别 第二部分:以 node.js 实现模块化规范 源码,深入学习. 一.模块规范 说到模块化加载,就不得先说一说模块规范.模块规范是用来约束每个模块,让其必须 ...
- SeaJS 模块化加载框架使用
SeaJS 是一个遵循 CMD 规范的模块化加载框架 CommonJS,CMD,AMD等规范后文会提到,这里主要先了解如何在代码中使用. 如果你有使用过nodejs ,那么理解起来就容易多了. 我们通 ...
- js模块化加载器实现
背景 自es6以前,JavaScript是天生模块化缺失的,即缺少类似后端语言的class, 作用域也只以函数作为区分.这与早期js的语言定位有关, 作为一个只需要在网页中嵌入几十上百行代码来实现一些 ...
- requirejs:性能优化-及早并行加载
为了提高页面的性能,通常情况下,我们希望资源尽可能地早地并行加载.这里有两个要点,首先是尽早,其次是并行. 通过data-main方式加载要尽可能地避免,因为它让requirejs.业务代码不必要地串 ...
随机推荐
- cp 覆盖 \cp a test\a
使用cp命令覆盖文件总是提示要输入yes或no,一个两个就算了,大量的文件复制就不行了,即使加上-f参数也无法强行覆盖.苦思冥想不得解,终于在查阅了众多资料后让我找到了解决方法,这里写出来,让有同样困 ...
- C# 连接SQL Server数据库的几种方式--server+data source等方式
如何使用Connection对象连接数据库? 对于不同的.NET数据提供者,ADO.NET采用不同的Connection对象连接数据库.这些Connection对象为我们屏蔽了具体的实现细节,并提供了 ...
- 一起来用css画画
hello,大白来了... <!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> ...
- allocator 类
allcator是一个模板类 定义在memory头文件中,将内存分配与对象构造分开,分配的内存是原始的.未构造的 一.how to use 因其实一个类,则使用allcator时需要首先声明一个类对象 ...
- C++primer 9.43
题目要求:编写一个函数,接受三个string参数s,oldVal和newVal.使用迭代器及insert和erase函数将s中所有oldVal替换为newVal.测试你的程序,用它替换通用的简写形式, ...
- IoC容器Autofac正篇之类型注册(五)
Autofac类型注册 类型注册简单的从字面去理解就可以了,不必复杂化,只是注册的手段比较丰富. (一)类型/泛型注册 builder.RegisterType<Class1>(); 这种 ...
- 使用 HTML5 input 类型提升移动端输入体验(键盘)
在最近的项目中,策划老是要求我们弹出各种类型的键盘,特别是在iOS下,例如输入帐号的时候,不应该支持输入中文,该输入纯数字的时候就应该谈数字键盘等.个人觉得这些都是我们平时开发很少意识到的,虽然有些刁 ...
- Inno Setup入门(四)——为程序创建桌面快捷方式
Icons这一可选段定义所有创建在开始菜单和\或其它位置 (比如桌面) 的快捷方式.一个例子如下: [setup] ;全局设置,本段必须 AppName=Test AppVerName=TEST De ...
- c++11 右值引用、move、完美转发forward<T>
#include <iostream> #include <string> using namespace std; template <typename T> v ...
- 转 由一次磁盘告警引发的血案:du 和 ls 的区别
如果你完全不明白或者完全明白图片含义, 那么你不用继续往下看了. 否则, 这篇文章也许正是你需要的. 背景 确切地说,不是收到的自动告警短信或者邮件告诉我某机器上的磁盘满了,而是某同学人肉发现该机器写 ...