Javascript模块化开发(二)——AMD 规范

像java有import模式可以引入其他人的开发的模块,而javascript没有。在javascript还没有官方模块化规范之前,CommonJS的目标是填补这个空缺。

node.js的模块系统,就是参照CommonJS规范实现的。在CommonJS中,有一个全局性方法require()就是用于加载模块。

CommonJS

CommonJS 标准大致如下:

  • 全局变量 exports:导出模块的方法,通过它导出的方法,便是这个模块的API。
  • 全局性的方法 require():用于加载模块。加载后,就可以调用模块的方法。
  • 创建一个addition.js 文件,代码如下:

    exports.do = function(a, b){ return a + b };
    			

    使用的时候只要如下代码就能使用

    var add = require('./addition');
    
    add.do(1,2) // 3
    			

node中还支持 exports返回一个对象,只需要它返回一个函数或者某个类的实例时,就要写成module.exports。

module.exports = function () {
  console.log("hello world")
}
			

CommonJS 的规范和代码可以看出,CommonJS规范加载模块是同步的。在服务器端node.js这貌似没问题,网络请求都是本地获取,对性能没多大影响。但是在浏览器断,问题就很严重了,需要很久时间所有模块才能全部加载完,这对于用户来说简直是恶梦。

所以CommonJs对于浏览器端是不足的,所以就有了AMD规范。

AMD规范

AMD是“Asynchronous Module Definition”的缩写,意思是:“异步模块定义”。

将我们的模块用 define 函数封装起来,并且异步加载模块。AMD规范的API如下:

define(id?, dependencies?, factory);
	
  • 第一个参数:String类型,表示模块的标识(也就是模块的路径,通过id才能知道从什么位置去加载依赖的模块)
  • 第二个参数:Array类型,数组元素是依赖模块的名字(id)
  • 第三个参数:回调函数,在依赖的模块加载成功后,会执行这个回调函数,它的参数是所有依赖模块的引用,如果回调函数有返回值,则导出。

完整的模块定义包含模块的id、依赖和回调函数,如下代码:

define("alpha", ["require", "exports", "beta"], function (require, exports, beta) {
     exports.verb = function() {
         return beta.verb();
         //Or:
         return require("beta").verb();
     }
});
	

如果省略第一个参数,则会定义一个匿名模块,

define(["alpha"], function (alpha) {
     return {
       verb: function(){
         return alpha.verb() + 2;
       }
     };
 });
	

在实际中,使用的更多的是匿名模块定义方式,这样子更灵活,开发人员可以修改代码时可以不用管这个模块放在何处。一般只有在要使用工具打包模块到一个文件中时,才会声明第一个参数,所以应该尽量避免给模块命名。

如果相互无依赖的可以直接定义

define({
   add: function(x, y){
     return x + y;
   }
 });
	

模块定义 CommonJS规范写法,如下:

define(function (require, exports, module) {
    var $ = require('jquery');
 
    ……
 
	var under = require('underscore');
 
    exports.action = function () {
        ……
    };
});
	

回调函数里的require在被调用时会自动加载,而无需想之前那样,在加载模块前就加载。

参数格式跟CommonJS一样。使用require获取依赖模块,使用exports导出对象,使用module导出函数。

AMD官方规范

目前,实现AMD的库有RequireJS 、curl 、Dojo 、bdLoadJSLocalnet 、Nodules 等。

RequireJS

AMD规范 是 RequireJS 在推广过程中对模块定义的规范化产生的。

所以我们接下来来看看 RequireJS 的用法。

在 home.html 文件中,只留下一个 script 标签:

<!DOCTYPE html>
<html>
<head>
    <title>arsenal home</title>
    
    <script data-main="js/home" src="js/require.js"></script>
</head>
<body>
<h1>arsenal home</h1>
</body>
</html>
	

使用requireJs的API,home.js则是作为其他js文件的入口,

require(["helper/jquery"], function ($) {
    // 当 scripts/helper/jquery.js 加载完毕,会回调函数

    //TODO
});
	

而定义模块以上我们讲 AMD 时已讲过,更多API

RequireJS 采用 head.appendChild() 的方式来加载所有依赖的脚本

加载非AMD规范的模块

在加载没有实现AMD规范的模块,可以通过配置定义这些模块的特征

requirejs.config({
    //要记住: 只能用shim来配置没有实现 AMD 规范的模块,而非已经实现 AMD 规范的模块
    shim: {
        'backbone': {
        	// 这些依赖脚本会在 backbone.js 加载前加载 
            deps: ['underscore', 'jquery'],
            //Once loaded, use the global 'Backbone' as the
            //module value.
            // 一旦加载完毕则导出 Backbone
            exports: 'Backbone'
        },
        'underscore': {
            exports: '_'
        },
        'foo': {
            deps: ['bar'],
            exports: 'Foo',
            init: function (bar) {
                return this.Foo.noConflict();
            }
        }
    }
});


define(['backbone'], function (Backbone) {
  return Backbone.Model.extend({});
});
		

jQuery插件

requirejs.config({
    shim: {
        'jquery.colorize': ['jquery'],
        'jquery.scroll': ['jquery'],
        'backbone.layoutmanager': ['backbone']
    }
});
		

本文源链接:http://www.html5jscss.com/amd-js.html

转载请注明《Javascript模块化开发(二)——AMD 规范》| html5jscss

评论关闭了.