Require.js
模块化的需求
早期的js的模块化机制十分简单,在需要多文件协同的情况下,只能依赖<script>
标记的加载,没有类似其它语言的import、package等管理等机制。而前端的需求越来越复杂,代码越编越多,如何更好地封装和共享代码?
- 需要将js代码库封装起来,只暴露指定的接口,即模块化
- 需要保证加载的js代码库之间不会产生作用域冲突
- 模块化需要遵循统一的规范,这样该模块才能被所有的前端应用所使用
- 需要提供便利的加载外部代码库的机制,如按名称引用和加载
- 模块化还应提供一些额外功能,如:版本兼容检查、插件扩展机制等
- 此外,还需要像其它语言一样,解决动态加载js文件的方法
AMD规范 与 Require.js
- AMD: Asynchronous Module Definition 异步模块加载机制,是js中关于如何编写可共享代码库的一组规范
- require.js 是一个基于AMD规范实现的文件和模块加载器,能够异步地加载动态的依赖
换言之,你如果希望编写可被广泛共享的代码库,且被引入时不会产生变量名冲突之类的问题,则编码时应当遵循AMD规范,然后调用者使用 require.js 来加载你的代码库,就可以避免前述的诸多问题。
- requireJS使用document.appendChild()方法将每一个依赖加载为一个script标签。
- requireJS等待所有的依赖加载完毕,计算出各模块定义函数的正确调用顺序,然后依次调用它们。
AMD 规范示例
// other-lib.js
define({
$: function(s){console.log(s)}
}
);
上述代码,定义了一个最简单的模块,该模块暴露一个名称为$
的函数
结合 require.js 使用
<script src="js/require.js"></script>
<script>
require.config({
baseUrl:'js/', // 配置所有被引用的库默认位于 js/ 目录下
paths:{
'jquery':'http://cdn.com/jquery.min',
'other':'other-lib'
}
});
require(['jquery','other'],function($,other){
$('#info').text('该字段不能为空!');
other.$("this is from other-lib");
});
</script>
</body>
- require.config定义了本地名字到文件实体的映射,即路由,如other => other-lib.js
- 基于路由,require函数将读取第一个参数中的库名字列表,然后依次加载对应的库文件
- 同时,基于AMD规范,将各库中
define()
函数所返回的对象引用作为回调函数(即require的第二个参数)的参数。上例中:$
源于jquery库的$
,而other-lib
库虽然也定义了$
,但是在主程序中,它有了命名空间other.$()
。这样,就有效地避免了名称冲突。
只有一个主函数的模块
// other-lib.js
define(function () {
return function (s){
function(s){console.log(s)}
};
});
//main.js
require(['jquery','other'],function($,other){
$('#info').text('该字段不能为空!');
other("this is from other-lib");
});
jquery与other这两个库虽然同时定义了一个$
函数,并且作为唯一的主函数,但在main.js即调用者代码里,requirejs将其映射成为了不同的名字
其它模块化规范
- https://github.com/cmdjs/specification/blob/master/draft/module.md
- 前端模块化和AMD、CMD规范 https://www.cnblogs.com/highsea90/p/4383895.html
- AMD、CMD、UMD https://www.jianshu.com/p/bd4585b737d7
参考阅读
- requireJS的用法 https://www.ruanyifeng.com/blog/2012/11/require_js.html
- 具体使用 https://www.hangge.com/blog/cache/detail_1702.html
- requireJS 从概念到实战 https://www.cnblogs.com/HCJJ/p/6611669.html