用一个例子读懂 RequireJS
来源:广州中睿信息技术有限公司官网
发布时间:2012/10/21 23:25:16 编辑:admin 阅读 931
例子来自官方,我稍微改造了一下,如下://project.html<!DOCTYPEhtml><html><head><title>requirejs</titl

例子来自官方,我稍微改造了一下,如下:

// project.html  <!DOCTYPE html>  <html>   <head>    <title>requirejs</title>    <!-- data-main attribute tells require.js to load               scripts/main.js after require.js loads. -->    <script data-main="scripts/main" src="scripts/require.js"></script>   </head>   <body>      </body>  </html>    // scripts/main.js  define(function(util){        require("helper/util");        alert('main factory')        return {a:1, b:2};  })    // scripts/helper/util.js  alert('util.js is loaded!')  


就这样三个文件,运行结果 "util.js is loaded" -> "main factory"。当然,这太简单了,我要说的这才刚开始。


data-main 属性有一个值 "scripts/main",注释也写了,表示当 require.js 加载完之后加载 scripts/main.js。

其实不仅如此,如果指定了这个属性,会把它的目录部分和文件部分拆开,即 scripts/ 和 main,之后会这么做:

  cfg.baseUrl = 'scripts/';

  cfg.deps = ['main'];

即配置一下 baseUrl 和 deps


接着,用这个配置对象去初始化默认Context,这个过程会判断默认Context 是否依赖别的模块,这里明显依赖 "main",所以需要context.require(it)


怎么做的呢?很简单,它做了两件事:

1. 把需要加载的依赖放进一个数组

2. 遍历该数组,加载依赖,并轮询加载状态


append 的 script 节点需要提一下:

可以看到 RequireJS 为节点加了两个自定义属性,分别表示 contextName 和 moduleName


动态创建的 script 节点当脚本执行完后,会发出onload事件(IE 就是 onreadstatechange),RequireJS 这时会在事件处理函数中进行检测,加载的模块是否同时也存在依赖?来看一段代码:

/**   * 这个方法是在 script 节点加载的脚本执行完之后才会执行。   * 1. 通过 event.target 或 event.srcElement 可以取到 script 节点   * 2. 获取节点的 data-requiremodule 属性时,如这里的 "main"   * 所以 moduleName 就是 "main"   *   * @param {String} moduleName   */  completeLoad: function (moduleName) {   var args;      // 队列分为 全局队列 和 context队列   //   // 一个被加载的模块,在它的define()中,会把该模块对应的[name, deps, callback]塞进队列   // 如果遵循一个文件一个模块的写法,队列里只有一个元素   // 如果一个文件写了多个模块,那队列里有多个元素   //   // 现在的问题是:到底塞进哪个队列呢?   // 因为 IE 通过 interactive 状态可以知道当前执行的 script 节点,   // 而 script 节点又绑定了 data-requirecontext 属性,所以可以拿到contextName   // 综上:IE 加入 context队列,非IE加入 全局队列   //   // 这句就表示把全局队列的元素加入context队列,并清空全局队列   // 这样便实现了浏览器的兼容   context.takeGlobalQueue();      // defQueue 即 context 队列   while (defQueue.length) {    args = defQueue.shift();      if (args[0] === null) {     // 如果[name, deps, callback]中name为null,即匿名模块     args[0] = moduleName;     break;    } else if (args[0] === moduleName) {     //Found matching define call for this script!     break;    } else {     // 如果一个文件出现多个define,才有可能进到这里,暂时可以无视这个分支     callDefMain(args);     args = null;    }   }      // callDefMain其实是main()的apply调用   // 它是定义模块的主函数,通过[name, deps, callback]构造模块   // 它会获取模块需要的依赖,如果是未加载的依赖,会加入context.paused数组   if (args) {    callDefMain(args);   } else {    // 如果加载的文件没有写成模块的形式,进到这里    callDefMain([moduleName, [], null]);   }        // 每加载完一个,context.scriptCount就-1      // 对浏览器来说,这没什么问题,但这有一个副作用      // checkLoaded() 会通过scriptCount判断是否要轮询加载状态      // 为了避免这个开销, 这里先-1   if (req.isAsync) {    context.scriptCount -= 1;   }      // 这个方法主要就是处理context.paused,即加载那些依赖   // 并会轮询是否完成加载,并在加载完成时,做一些事   resume();   if (!req.isAsync) {    context.scriptCount -= 1;   }  }  


本文仅作了解,更多的内容我会单独写文章讲解

联系我们CONTACT 扫一扫
愿景:成为最专业的软件研发服务领航者
中睿信息技术有限公司 广州•深圳 Tel:020-38931912 务实 Pragmatic
广州:广州市天河区翰景路1号金星大厦18层中睿信息 Fax:020-38931912 专业 Professional
深圳:深圳市福田区车公庙有色金属大厦509~510 Tel:0755-25855012 诚信 Integrity
所有权声明:PMI, PMP, Project Management Professional, PMI-ACP, PMI-PBA和PMBOK是项目管理协会(Project Management Institute, Inc.)的注册标志。
版权所有:广州中睿信息技术有限公司 粤ICP备13082838号-2