CommonJS规范不适用于浏览器环境,这对服务器端不是一个问题,因为所有的模块都存放在本地硬盘,可以同步加载完成,等待时间就是硬盘的读取时间。但是,对于浏览器,这却是一个大问题,因为模块都放在服务器端,等待时间取决于网速的快慢,可能要等很长时间,浏览器处于”假死”状态。
因此,浏览器端的模块,不能采用”同步加载”(synchronous),只能采用”异步加载”(asynchronous)。这就是AMD规范诞生的背景。AMD也采用require()语句加载模块,但是不同于CommonJS,它要求两个参数:require([module], callback);第一个参数[module],是一个数组,里面的成员就是要加载的模块;第二个参数callback,则是加载成功之后的回调函数。
使用requireJS的优点有哪些?

  1. 实现JS文件的异步加载,避免网页被堵塞。
  2. 管理模块之间的依赖性,便于代码的编写和维护。
    require.js要求,每个模块是一个单独的js文件。这样的话,如果加载多个模块,就会发出多次HTTP请求,会影响网页的加载速度。因此,require.js提供了一个优化工具,当模块部署完毕以后,可以用这个工具将多个模块合并在一个文件中,减少HTTP请求数。

引入步骤:

  • 在页面头部head标签内引入requireJS,如下:<script src=”js/require.js”></script>,但是加载这个文件也会造成网页失去响应,我们可以加上defer和async这个属性。如下:<script src=”js/require.js” defer async=”true” ></script>,Async属性表明文件需要异步加载,IE不支持这个属性,只支持defer,所以上面把这2个属性都加上。
  • requireJS启动加载脚本的初始化方式,requireJS支持属性data-main这个属性来加载初始化的JS文件,如下:>script src=”js/require.js” defer async=”true” data-main=”js/main.js”></script< 上面的意思是:先异步加载requireJS文件,完成后继续异步加载app.js文件。上面的app.js后的.js可以去掉,因为requireJS源码已经默认都是以后缀JS文件结尾的。
  • data-main属性所指的js我把它称为”主模块”,意思是整个网页的入口代码。它有点像C语言的main()函数,所有代码都从这儿开始运行。

模块步骤:

  • RequireJS编写模块不同于其他脚本文件,它良好的使用define来定义一个作用域避免全局空间污染,它可以显示出其依赖关系,并以函数(定义此模块的那个函数)参数的形式将这些依赖进行注入。
  • define中直接返回一个对象,可以解决全局变量的理念。比如全局变量全部使用define函数包围,什么时候需要全局变量的话,直接require([‘XX’],function(XX){})这样调用下。
  • 使用require.config()方法,我们可以对模块的加载行为进行自定义。require.config()就写在主模块(main.js)的头部。
  • If a module ID has one of the following characterstics, the ID will not be passed through the “baseUrl + paths” configuration, and just be treated like a regular URL that is relative to the document:
    Ends in “.js”. Starts with a “/“.
    *Contains an URL protocol, like “http:” or “https:”。

AMD模块定义

1
2
3
4
5
6
7
8
9
10
       //包装模块  使用exports或者module.exports导出API
define(function(require, exports, module) {
//require require函数
//exports exports空对象 被注入对象
//module module模块对象 含有id、uri等 ***id:"app/faq" ***uri:"js/app/faq.js"
var base = require('base'); //可拿到了
exports.show = function() {
//todo with module base
}
});

requireJS配置项

  • baseUrl:指定本地模块的基准目录,即本地模块的路径是相对于那个目录的。该属性通常有requireJS加载时的data-main属性指定。如果未显示设置baseUrl,则默认值是加载require.js的html所处的位置,如果使用了data-main属性的话,则该路径变成了baseUrl。
  • paths:paths是映射那些不直接放在baseUrl指定的目录下的文件,设置paths的起始位置是相对于baseUrl的,除非该paths设置是以”/”开头或含有URL协议(http://或者https://).
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // 关键点是确定目录   默认是在lib下加载  当是app时就是app下
    requirejs.config({
    baseUrl: 'js/lib',
    paths: {
    app: '../app'
    }
    });
    requirejs(['app/a'],function(a){

    });

shim参数

  • 解决了使用非AMD方式定义的模块(如jquery插件)及其载入顺序,为那些没有使用define()来声明依赖关系,设置模块的”浏览器全局变量注入”型脚本做依赖和导出配置。
  • 也就是说shim这个参数可以解决没有使用define(function(){})这样的文件包围的代码或者一些全局变量注入,可以确保此文件先加载,然后再加载其他文件。
  • shim属性,专门用来配置不兼容的模块。具体来说,每个模块要定义(1)exports值(输出的变量名),表明这个模块外部调用时的名称;(2)deps数组,表明该模块的依赖性。

    1
    2
    3
    4
    5
    6
    7
    //jQuery的插件可以这样定义
    shim: {
        'jquery.scroll': {
          deps: ['jquery'],
          exports: 'jQuery.fn.scroll'
        }
      }
  • 如果我不使用shim这个参数的话,在最新版的requirejs2.1.15中(以前的版本我不太清楚),也可以通过require([‘XX’])来解决,如下演示:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     global.js代码如下:
    names = 1111;
    创造一个全局变量names,其中js/app/depBase.js代码如下:
    define(function(){
    return {
    'name':names
    }
    })

    也就是说我在app.js代码如下初始化如下:
    require.config({
    baseUrl: 'js/app'
    });
    require(['global','depBase'],function(global,base){
    console.log(base);
    });
    我先global初始化引入全局变量names,接着打印出depBase的返回值。也可以看到,可以引入到全局变量names的值。

Map参数

  • Map参数是用来解决同一个模块不同版本的问题。比如在项目开发中,开发初期使用了jquery1.7版本,但是由于业务的需求需要引入jquery1.9以上的版本时候,但是又担心有些是依赖于jquery1.7的代码升级到1.9以上的时候会有问题,因此可以让一部分代码还是依赖于jquery1.7,新增的代码依赖于jquery1.9。

config参数

  • config是指需要将配置信息传给一个模块,这些配置往往是application级别的信息,需要一个手段将他们向下传递给模块。在requireJS中,基于requirejs.config()的config配置项来实现。要获取这些信息的模块可以加载特殊的依赖”moudle”,并调用module.config().

    1
    2
    3
    4
    5
    6
    //加载特殊的依赖"moudle"
    define(['module'], function (module) {
    //Will be the value 'blue'
    var color = module.config().color;
    return color;
    });

    requireJS函数增加了第三个参数errbacks。

    1
    2
    3
    4
    5
    require(['b'], function ($) {
    //Do something with $ here
    }, function (err) {
    alert(err);
    });

    在模块载入失败回调中可以使用undef函数移除模块的注册。

    1
    2
    3
    4
    5
    6
    7
    8
    require(['b'], function ($) {
    //Do something with $ here
    }, function (err) {
    var failedId = err.requireModules && err.requireModules[0];
    if (failedId === 'b') {
    requirejs.undef(failedId);
    }
    });

require.js插件

  • require.js还提供一系列插件,实现一些特定的功能。domready插件,可以让回调函数在页面DOM结构加载完成后再运行。text和image插件,则是允许require.js加载文本和图片文件。


requireJS对文件合并与压缩:

  • node r.js –o baseUrl=js name=app out=build.js
  • node r.js –o baseUrl=js name=app out=build.js optimize=none
    下面我们对命令分别来做一下解释:
    -o: 表示优化,该参数是固定的,必选。
    baseUrl:指存模块的根目录,可选。
    name: 模块的入口文件,这里是app,那么r.js会从baseUrl+name去查找app.js,然后找出所有依赖的模块,然后进行合并与压缩。
    out: 指合并压缩后输出的文件路径,这里是直接输出在根目录下build.js 我们也可以输出到其他目录下 比如js/app 目录下,也可以的。
    optimize=none:只合并不压缩。

Comments

去留言
2016-06-13

⬆︎TOP