使用RequireJS实现异步加载脚本

关于Require的使用

因为 javascript 天生的缺点,语言本身没有集成命名空间的概念,所以变量名、函数名很容易发生冲突。大家想尽了各种办法,给 js 添加命名空间的概念,其中最成熟的套路,就是 RequireJS 这种。

总之,RequireJS 定义了(define)一个命名空间,在定义的时候,顺便引用了需要使用其他命名空间。我们注意到,按照 RequireJS 的术语,它把命名空间叫做“模块”。注意,在这里,RequireJS 定义的模块(命名空间)是匿名的,没有取名,这是和c#不同的地方。

但这个不要紧,因为其他 js 在用到你这个 js 的时候,一般是根据文件名称加载的,同时可以通过上面的 xx 这种方式,给模块(命名空间)自定义别名,所以,取不取名,还真不是关键。

Require配置

页面中要加载require.js并指明主要入口文件。

<!--data-main="main",等号右边的main指的main.js,相当于入口-->
<script type="text/javascript" data-main="<%=path%>/lib/main" src="<%=path%>/lib/require.js"></script>

对于入口文件中作如下设置:

require.config({
    urlArgs : "timestamp=" + (new Date()).getTime(),
    waitSeconds: 60,
    paths : {
            // 省略.......
        userModel:"modules/userModel",
        userCollection:"modules/userCollection"
    },

    shim : {

        bootstrap : {
             deps : [ "jquery" ],
             exports : "$.fn.popover"
        },

    bootstrap_datetimepicker : {
         deps : [ "jquery", "bootstrap" ],
         exports : "$.fn.datetimepicker"
    },

    jqueryIfrmdailog : {
        deps : [ "jquery" ],
        exports : "$.ShowIfrmDailog"
    },        
   }
});

var requirArray = ["jquery", "jqueryUI"];

require(requirArray, function($, jqueryUI) {
    //
});

参数说明:

baseUrl: 查找所有模块的根路径。

urlArgs :RequireJS 用来匹配资源的额外的URL的查询参数 。通常的用法是在浏览器或者服务器配置不对的时候禁用缓存。

waitSeconds: 放弃加载脚本前的等待的秒数。 设置为 0 则禁用此功能。默认是 7 秒。

paths: 映射到不能直接在baseUrl下找到的模块名。 通常, path设置的路径是相对于baseUrl 的,除非 以 “/“ 开头或包含URL协议 (例如” http:”)。path的设置不要加.js后缀,因为path也可能是映射到一个目录。 如果path映射的是一个模块,RequireJS会自动加上.js后缀。

shim: 为那些没有使用define() 声明依赖项、没有设置模块值、老的、传统的”浏览器全局”脚本配置依赖项和exports。

map: 对于给定的相同的模块名,加载不同的模块,而不是加载相同的模块。

config: 传递一个配置信息到模块中是一个常见的需求。这个配置信息通常是应用的一部分,我们需要把它传递到模块中。 在 RequireJS 中,requirejs.config()中的config配置项 就是为了解决这个需求。 模块中可以通过内置依赖模块”module” ,通过调用module.config()方法来获取传递进来的配置信息.

packages: 配置从CommonJS 包来加载模块.

context: 加载上下文配置(require.config的对象)的名字。 只要顶级 require调用指定一个唯一context字符串,require.js就可以在一个页面中加载多个版本的模块。

deps: 需要加载的依赖项的数组。当在require.js加载前使用全局 require对象来定义配置的时候很有用,也可以在require()一定义后就马上加载指定依赖项的时候用。

callback: 所有依赖项加载后执行的回调函数。

enforceDefine: 如果设置为true, 当加载的脚本是没用define()包装过,且在shim配置中没有配置exports值时会抛错。

xhtml: 如果设置为 true,requireJS 将使用document.createElementNS() 来创建script标签。

scriptType: 设置 RequireJS生成的 script 标签的 type属性值。默认是”text/javascript”。

require关键字就是一个加载方法,加载的时候,可以定义别名;除了这种方法外,还可以用define,define是你定义自己的模块的时候使用,可以顺便加载其他的js。


define定义模块

define(["jquery"], function($){

    var util = {};
    util._helper = {};

    // 日期格式化输出
    util._helper.dateFormat = function(date , fmt) { //author: meizz 

        if (date == null || ! (date instanceof Date)) {
            return "";
        }

        var o = {
            "M+" : date.getMonth() + 1, //月份 
            "d+" : date.getDate(), //日 
            "h+" : date.getHours(), //小时 
            "m+" : date.getMinutes(), //分 
            "s+" : date.getSeconds(), //秒 
            "q+" : Math.floor((date.getMonth() + 3) / 3), //季度 
            "S" : date.getMilliseconds()
        //毫秒 
        };
        if (/(y+)/.test(fmt))
            fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "")
                    .substr(4 - RegExp.$1.length));
        for ( var k in o)
            if (o.hasOwnProperty(k) && new RegExp("(" + k + ")").test(fmt))
                fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
        return fmt;
    };

    return util;
});

其他

  • 路径与后缀名

    在 require 一个 js 文件的时候,一般不需要加上后缀名。如果加上后缀名,会按照绝对路径加载。没有后缀名,是按照下面的路径加载:


  • 也就是默认加载 data-main 指定的目录,即 js/main.js 文件所在的目录。当然,你可以通过配置文件修改。
  • define 定义模块方法只能用在独立的js文件中,不能在页面中直接使用。
    否则会报 Mismatched anonymous define() module 错误。
  • 和其他第三方js类库是否冲突?

    不会冲突。一般比较规范的类库,都会给自己的js加上命名空间。比如 wojilu 旧有的 wojilu.common.js ,其实就是放在 wojilu 命名空间中(当然是通过更原始的方式实现命名空间的)。

    在通过 RequireJS 加载这些第三方的 js 的时候,完全不要有任何担忧。

    当然,如果第三方类库能够使用 RequireJS 的方式进行改造,那是最好。比如 wojilu 中大多数js 都按照 RequireJS 的方式进行了改造。但是,如果你不改造,也是完全不要紧的。

  • 在代码中 require 一个文件多次,是否会导致浏览器反复加载?

    不会,这是 RequrieJS 的优点,即使你反复 require 它,它只加载一次。

本站总访问量