4.4 Require.js的使用方法
前文介绍了在现代化开发中大量由前端模块化方案引发的问题,本节就回归到本章的主角Require.js上,尽管现代化前端开发中几乎已经不再使用Require.js来进行模块管理了,但它仍然是一个值得学习的优秀的JavaScript库,而且谁又能确保自己的工作永远不需要再维护旧代码呢?Require.js在设计上遵循多态原则,虽然核心API非常精简,但其包含了多种场景的函数重载,同时条件分支也被封装了起来,以简化用户的使用。require.config()方法用于传入基本配置,define()方法用于定义模块,require()方法用于引入模块,下面通过一个实例讲解其基本用法。
首先定义两个业务逻辑模块,代码如下:
/** scripts/business1.js * 第一个模块采用依赖前置的风格定义 */ define('business1',['jQuery'],function(){ function welcome(){ $('#welcome-modal').animate({opacity:1},2000); } return { welcome } }); /** scripts/business2.js * 第二个模块采用依赖就近的风格定义,且不指定模块名 */ define(function(require,exports,module){ require('jQuery'); exports.showPrototype = function(){ return $.prototype; } });
然后在index.html文件中引用Require.js,代码如下:
/** index.html * 可以看到,index.html文件中引入了Require.js后,模块管理部分的代码实际上转移到了main.js文件中 */ <script data-main="main.js" src="require.js"></script>
最后在main.js中编写基本配置并运行启动方法,代码如下:
/** main.js * require.js的配置项还有很多,详情请参考官方文档 */ require.config({ paths:{ jQuery:'scripts/jquery.min', business1:'scripts/business1.js', } }); //依赖使用注册的模块Id或文件路径均可 require(['business1','./scripts/business2.js'],function(bus1,bus2){ bus1.welcome(); console.log(bus2.showPrototype()); });
1. 代码执行流程
前面的代码在执行时,index.html会先通过外部脚本加载Require.js库,标签上通过“data-*”传入的自定义属性是可以被脚本代码获取到的,Require.js完成加载和初始化后就会下载并执行data-main所指向的入口文件。在main.js中,先通过require.config()传入一些基本配置,例如用显式id注册模块的名称和模块定义文件的地址,接着开始执行正式的逻辑。“require”语句声明了两个模块依赖,由于'business1'模块已经在config中进行了注册,因此根据注册地址就可以加载并执行模块文件,而'./scripts/business2.js'模块并没有进行初始化声明,此时Require.js会将其视作路径地址,并尝试获取对应的脚本文件,如果获取失败则会报错,表示所依赖的模块并没有定义。不过,这两个业务逻辑模块中依赖的jQuery模块在config中已经注册了,模块加载系统可以直接识别它们(jQuery加载后会直接挂载在全局对象中,有的版本有返回值,有的版本则没有)。依赖分析完成后,Require.js就会按照被依赖的次序开始从依赖树的末端加载并执行各个模块,待'business1'模块和'./scripts/business2.js'模块加载完之后,require方法中传入的最后一个实参函数才会得到调用和执行,执行结果是页面上id为'welcome-modal'的元素在2秒内逐渐变为可见,同时控制台会打印出jQuery对象的原型对象。
2. 实用性
Require.js库不仅实现了符合AMD规范的模块管理方案,还在工程实践中为开发者提供了许多便捷的功能,如引用模块时自动添加时间戳以便强制使用最新的代码,或者为非AMD模块提供shim包装等,更多的功能请参考官方文档进行学习。如果流行的自动化工具链让你觉得过于复杂,难以掌握,那么你完全可以从使用Require.js开始着手来学习模块化的相关知识,以了解在模块管理和加载中需要解决的问题,以及Require.js提供的解决方案。虽然我们使用的工具在不断升级,但需要解决的软件工程问题是一致的。