概述
node作为一个服务端语言,在加载模块时,模块都是在本地磁盘,因此可以以可观的速度加载进来,因此,在node里的模块加载都是同步的,阻塞时间都不会太长。 如果我们要在浏览器端的js来实现模块设计模式呢,这就意味着我们需要远程从服务器加载所以定义的模块,浏览器js引擎的阻塞时间可想而知。 如果不使用模块设计模式的话,那各个js文件互相依赖,而且共享一个顶层作用域window,很容易出现变量重定义的错误。比如下面这种形式。
<script src="js/test1.js" type="text/javascript" charset="utf-8"></script>
<script src="js/test2.js" type="text/javascript" charset="utf-8"></script>
<script src="js/test3.js" type="text/javascript" charset="utf-8"></script>
<script src="js/test4.js" type="text/javascript" charset="utf-8"></script>
<script src="js/test5.js" type="text/javascript" charset="utf-8"></script>
<script src="js/test6.js" type="text/javascript" charset="utf-8"></script>
各个文件互相依赖,耦合性很高。
但是如果我们要用模块设计模式的话,那么各个模块必须用异步加载,如果不用异步加载,浏览器很可能处于很长时间的阻塞状态,造成很糟糕的用户体验。因此AMD孕育而生。
AMD 模块定义
define(id,arr[],function(){});
define 接受3个参数,id是模块化标识可以省略,第二个参数可以省略,在没有依赖于其他模块的情况下,可以将第一个参数省略,因此,我们可以这样定义。
define(() => {
let sum = (x,y) => {
return x + y;
};
return {sum:sum}
});
与commonJS 也有一些相似之处,commonJS 暴露给外部的接口为module.exports 所指向的对象,而AMD 暴露给外部的接口为return 的对象, 这里我暴露了一个json对象,key 为外部调用的名称,value 为名称指向的对象。
如果我们定义的模块依赖于其他的模块,比如我们依赖于一个hello的模块。
这时,我们的模块需要这样定义:
define(['hello'],() => {
let sum = (x,y) => {
return x + y;
};
return {sum:sum}
});
定义数据对象模块 (data.js)
define({
users: [],
members: []
});
RequireJS
RequireJS
现在有很多AMD规范的库 RequireJS就很不错········呵呵呵别的懒得看了而已
看个极简的例子:
首先要到requirejs的网站去下载require.js
<!DOCTYPE html>
//index.html
<html>
<head>
<script type="text/javascript" src="require.js"></script>
<script type="text/javascript">
require(["a"]);
</script>
</head>
<body>
<span>body</span>
</body>
</html>
//a.js
define(function(){
function fun1(){
alert("it works");
}
fun1();
})
requireJS 定义了三个变量:define,require,requirejs,其中requirejs===require,一般用require 因为懒是天性。
- define 定义一个模块。
- require 加载依赖模块,并执行加载完成后的回调函数。
通过define函数定义了一个模块,然后再页面中使用:
require(["js/a"]);
来加载该模块(注意require中的依赖是一个数组,即使只有一个依赖,你也必须使用数组来定义),require API的第二个参数是callback,一个function,是用来处理加载完毕后的逻辑,如:
require(["js/a"],function(){
alert("load finished");
})
RequireJS全局配置
我们可以通过require.config来配置复杂的加载文件
require.config({
paths : {
"jquery" : ["http://libs.baidu.com/jquery/2.0.3/jquery","js/jquery"],
"a" : "js/a"
}
})
paths还有一个重要的功能,就是可以配置多个路径,如果远程cdn库没有加载成功,可以加载本地的库.
我们不可能每个文件都写require.config,requirejs提供了一种叫”主数据”的功能,我们首先创建一个main.js
//main.js
require.config({
paths : {
"jquery" : ["http://libs.baidu.com/jquery/2.0.3/jquery", "js/jquery"],
"a" : "js/a"
}
})
//通过data-main这种方式来使用
<script data-main="js/main" src="js/require.js"></script>
加载requirejs脚本的script标签加入了data-main属性,这个属性指定的js将在加载完reuqire.js后处理,我们把require.config的配置加入到data-main后,就可以使每一个页面都使用这个配置,然后页面中就可以直接使用require来加载所有的短模块名
data-main还有一个重要的功能,当script标签指定data-main属性时,require会默认的将data-main指定的js为根路径
RequireJS shim
为那些没有使用define()来声明依赖关系、设置模块的”浏览器全局变量注入”型脚本做依赖和导出配置。
require.config({
shim: {
"backbone" : {
//在加载backbone.js之前应先加载它的依赖函数underscore.js和jquery.js
deps: ['underscore', 'jquery'],
//加载完毕后该模块使用的引用名
exports: 'Backbone'
}
}
})