1、综述:

  RequireJS的目标是代码的模块化,它使用了不同于传统<script>标签的脚本加载步骤。

可以用它来加速代码加载、优化代码,但其主要目的还是为了代码的模块化。

2、加载js文件

   RequireJS以一个相对于baseUrl的地址来加载所有的代码。 <script>标签含有一个特殊的属性data-main,require.js使用它来启动脚本加载过程,(其中data-main是入口,想当于java的main方法)而baseUrl一般设置到与该属性相一致的目录:

 <script data-main="scripts/main.js" src="scripts/require.js"></script>

 这样的设置,baseUrl指向到了scripts目录,当然baseUrl可以手动的指定,也就是requirejs.config({})配置,如果没有显式配置,baseUrl默认指向引用requirejs的html所在的目录。

3、例子解析,目录结构:

  www/
	-index.html
	-js/
	---app/
	------sub.js
	---lib/
	------jquery.js
	------canvas.js
	---app.js

 index.html中的片段

<script data-main="js/app.js" src="js/require.js"></script>

 文件入口app.js

 requirejs.config({
	baseUrl: 'js/lib', 
	paths: {
		app: '../app'
	}
	});
	// Start the main app logic.
	requirejs(['jquery', 'canvas', 'app/sub'],
	    function   ($, canvas, sub) {
	      //jquery,canvas,sub 资源都已经加载完毕,可以用了。
	}); 
  });	

  baseUrl为加载文件的起始位置,不过请注意的是paths配置(paths是路径相对于baseUrl而言的,加载的文件都不需要.js后缀,因为requirejs默认依赖资源为js文件,如果加上了后缀,则会加载报错),这里配置的意思是,如果以“app”开始的Module ID(baseUrl+paths),则js/app 加载。

4、requirejs核心

   (1)定义模块

    模块不同于传统的脚本文件,它良好地定义了一个作用域来避免全局名称空间污染。还可以显式地列出其依赖关系,并将其依赖注入进来。

    定义简单的对象:

   define({
        name: "hcc0926",
	age: "3"
	});

定义一个方法,没有外部依赖:

   define(function () {
	return {
		name: "hcc0926",
		age: "3"
	    }
	});

定义一个方法,包含外部依赖:

先看个例子,该模块依赖bb.js 和 aa.js:

    define(["./aa", "./bb"], function(aa, bb) {
       return {
         name: "hcc0926",
		  age: "3",
         addToCart: function() {
            aa.xxx();
            bb.add();
         }
       }
    });

  define中的一个参数是个数组,就依赖项,第二个参数是个function(即模块的定义是在该方法体中定义),等所有的依赖项加载完成后执行第二个参数function,依赖关系会以参数的形式注入到该函数上,参数列表与依赖名称列表一一对应(名称可以不一致)。如果你对js比较熟悉的话,就会明白,function中不止可以返回对象,还可以返回方法,即如下形式:

define(["./aa", "./bb"], function(aa, bb) {
    return function(){
	  return aa.xxx();
	}    
 });

当然你可以可以指定module名称:

define("moduleId",["aa", "bb"],function(aa, bb) {
     //Define module in here.
});

 

  (2) 包装成commonJs的风格

    如果你现有一些以CommonJS模块格式编写的代码,而这些代码难于使用上述依赖名称数组参数的形式来重构,你可以考虑直接将这些依赖对应到一些本地变量中进行使用。你可以使用一个CommonJS的简单包装来实现:

    define(function(require, exports, module) {
        var a = require('a'),
        b = require('b');
        //Return the module value
        return function () {};
     });

   或者也可以写出下面的形式,通过exports把本模块中的接口暴露给外部,供其他地方调用

    define(function(require, exports, module) {    
      var a = require('a'),b = require('b');
        exports.add = a.xxx()+b.xxx();
    });

5、其他需要注意点

   (1)一个文件定义一个模块

   (2)define()中的相对模块名: 为了可以在define()内部使用诸如require("./relative/name")的调用以正确解析相对名称,记得将"require"本身作为一个依赖注入到模块中:

        define(["require", "./relative/name"], function(require) {
	    var mod = require("./relative/name");
	});

这样看着也比较别扭,可以通过commonJS的风格来改造成下面的形式:

        define(function(require) {
	    var mod = require("./relative/name");
	});

(3)生成相对于模块的URL地址:如果你想生成某个引用文件的url,可以使用以下形式:

         define(["require"], function(require) {
	     var cssUrl = require.toUrl("./style.css");
	 });

     (4)加载非AMD规范的文档:

对于backbone,underscore,已经其他的非AMD规范的需要借助requirejs.config({})中的         shim:

    requirejs.config({
        baseUrl : {},
        shim: {
            'backbone': {
                deps: ['underscore', 'jquery'], //backbone的依赖库
                exports: 'Backbone' //backbone对外暴露的接口
            },
            'underscore': {
                exports: '_'
            }
	}
	});
   //在其他的文件中就可以通过如下形式访问了,
	define(['backbone'], function (Backbone) {
	  return Backbone.Model.extend({});
	});

    使用shim的注意点:

      1-shim配置仅设置了代码的依赖关系,想要实际加载shim指定的或涉及的模块,仍然需要一        个常规的require/define调用。设置shim本身不会触发代码的加载。

      2-请仅使用其他"shim"模块作为shim脚本的依赖

      3-不要混用CDN加载和shim配置 

(5)map: 对于给定的模块前缀,使用一个不同的模块ID来加载该模块。

        requirejs.config({
		map: {
			'some/newmodule': {
				'foo': 'foo1.2'
			},
			'some/oldmodule': {
				'foo': 'foo1.0'
			}
		}
	});

    (6)requirejs.config中的其他配置:

    config:这些配置往往是application级别的信息,需要一个手段将它们向下传递给模            块

    packages: 从CommonJS包(package)中加载模块。参见从包中加载模块。

    还有context,xhtml,urlArgs,callback等,请参考                    http://requirejs.org/docs/api.html

(7)多版本支持,加载插件,定义国际化组件

暂时没有使用过,后续讨论。


附一个比较好的amd教程

http://efe.baidu.com/blog/dissecting-amd-what/