码迷,mamicode.com
首页 > Web开发 > 详细

用一个例子读懂 RequireJS

时间:2017-06-14 22:15:27      阅读:277      评论:0      收藏:0      [点我收藏+]

标签:bre   images   构造   syntax   active   rem   x11   htm   number   

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

// 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 这时会在事件处理函数中进行检测,加载的模块是否同时也存在依赖?来看一段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/**
 * 这个方法是在 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;
    }
}

 

用一个例子读懂 RequireJS

标签:bre   images   构造   syntax   active   rem   x11   htm   number   

原文地址:http://www.cnblogs.com/liangxiaoli/p/7011094.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
分享档案
周排行
mamicode.com排行更多图片
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!