第2章 模块加载系统
任何语言一到大规模应用阶段,必然要经历拆分模块的过程,以有利于维护与团队协作。与Java 走得最近的 dojo 率先引入了加载器,早期的加载器都是同步的,使用 document.write 与同步Ajax请求实现。后来dojo开始以JSONP的方法设计它的每个模块的结构,以script节点为主体加载它的模块,这个就是目前主流的加载器方式。不得不提的是,dojo的加载器与AMD规范的发明者都是James Burke,dojo加载器独立出来就是著名的require加载器。本章将为你深入理解加载器的原理,讲授样本为mass并行加载器。你可以到这里下载:
https://github.com/RubyLouvre/mass-Framework/blob/master/mass.js
2.1 AMD规范
AMD是“Asynchronous Module Definition”的缩写,意为“异步模块定义”。重点有两个。异步——有效避免了采用同步加载方式中导致的页面假死现象。模块定义——每个模块必须按照一定的格式编写。主要接口有两个,define与require。define是模块开发者关注的方法,require是模块使用者关注的方法。
define的参数情况为define(id?, deps?, factory)。第一个为模块ID,第2个为依赖列表,第3个是工厂方法。前两个都是可选,如果不定义 ID,则是匿名模块,加载器运用一些“魔术”能让它辩识自己叫什么。通常情况,模块ID约等于模块在工程中的路径(放到线上,表现为URL)。在开发过程,许多情况未确定,一些JavaScript文件会移来移去的,因此匿名模块就大发所长。deps与factory有个约定,deps有多少个元素,factory就有多少个传参,位置一一对应。传参为其他模块的返回值。
define("xxx", ["aaa","bbb"], function (aaa,bbb){ });
通常情况下define中还有一个amd对象,里面储存着模块的相关信息。
require的参数情况为require(deps, callback),第一个为依赖列表,第2个为回调。deps有多少个元素,callback就有多少个传参,情况与define方法一致。因此在内部,define方法会调用require来加载依赖模块。一直这样递归下去。
require(["aaa","bbb"], function(aaa,bbb){ })
接口就是这么简单,但 require 本身还包含许多特性比如使用“!”来引入插件机制,通过requirejs.config进行各种配置。模块只是整合的一部分,你要拆得开,也要合得拢,因此合并脚本的地位在加载器中非常重要。但前端JavaScript没有这功能,requirejs利用node.js写了个r.js帮你进行合并。