RequireJS源码解读(二)

(续上节)
上面讲了如何处理全局序列和context化全局序列
以及执行全局序列中的依赖项。
检查依赖项

   //Mark all the dependencies as needing to be loaded.
                    context.nextTick(function() {
                        //Some defines could have been added since the
                        //require call, collect them.
                        intakeDefines();

                        requireMod = getModule(makeModuleMap(null, relMap));

                        //Store if map config should be applied to this require
                        //call for dependencies.
                        requireMod.skipMap = options.skipMap;

                        requireMod.init(deps, callback, errback, {
                            enabled: true
                        });

                        checkLoaded();
                    });

最后返回的是 return localRequire;

回到 context.require(deps, callback, errback);

4. 监听页面加载

传入的参数是load加载事件
脚本加载的回调,用于检查加载状态。

 onScriptLoad: function(evt) {
                //Using currentTarget instead of target for Firefox 2.0's sake. Not
                //all old browsers will be supported, but this one was easy enough
                //to support and still makes sense.
                if (evt.type === 'load' ||
                    (readyRegExp.test((evt.currentTarget || evt.srcElement).readyState))) {
                    //Reset interactive script so a script node is not held onto for
                    //to long.
                    interactiveScript = null;

                    //Pull out the name of the module and the context.
                    var data = getScriptData(evt);
                    context.completeLoad(data.id);
                }

var data = getScriptData(evt) 这个函数 构造完毕之后,将返回一个对象

这里写图片描述
此时data就是{ node:script对象,id : ‘main’ }

5.获取加载对象

开始加载

 completeLoad: function(moduleName) {
                var found, args, mod,
                    shim = getOwn(config.shim, moduleName) || {},
                    shExports = shim.exports;

                takeGlobalQueue();

                while (defQueue.length) {
                    args = defQueue.shift();
                    if (args[0] === null) {
                        args[0] = moduleName;
                        //If already found an anonymous module and bound it
                        //to this name, then this is some other anon module
                        //waiting for its completeLoad to fire.
                        if (found) {
                            break;
                        }
                        found = true;
                    } else if (args[0] === moduleName) {
                        //Found matching define call for this script!
                        found = true;
                    }

                    callGetModule(args);
                }
                context.defQueueMap = {};

                //Do this after the cycle of callGetModule in case the result
                //of those calls/init calls changes the registry.
                mod = getOwn(registry, moduleName);

这里写图片描述

运行到这里,callGetModule()就是调用module了吧
这里写图片描述

     function callGetModule(args) {
            //Skip modules already defined.
            if (!hasProp(defined, args[0])) {
                getModule(makeModuleMap(args[0], null, true)).init(args[1], args[2]);
            }
        }

传入的args :args = [“main”, Array[0], undefined]
args[1]和args[2]到底是来干嘛的?

5.1 创造ModuleMap对象

首先makeModuleMap(args[0], null, true)).init(args[1], args[2]
从下图可以看到args[1]是当前加载项的父节点, args[2]->applyMap?:
这里写图片描述

转化为绝对路径

最后将main.js转化为url路径,可能在这里没什么用,但是在这种定义了baseURL或者重命名模块中,这个normolize显得非常有用的
这里写图片描述

最后得到的对象:

这里写图片描述

5.2 getModule

这里写图片描述

5.3 Module.init

这里写图片描述

5.4 checkLoaded()

checkLoaded()会调用onScriptLoad(),出现了新的./@r5.js 是a.js吗
这里写图片描述
然而不是a.js,第二次遍历加载出了a.js
这里写图片描述

又见到熟悉的@r5.js,这次它变成了Module
这里写图片描述

6 加载第一个script:a.js

 req.load = function(context, moduleName, url) {
        var config = (context && context.config) || {},
            node;
        if (isBrowser) {
            //In the browser so use a script tag
            node = req.createNode(config, moduleName, url);

            node.setAttribute('data-requirecontext', context.contextName);
            node.setAttribute('data-requiremodule', moduleName);
6.1 检测是否是浏览器
 isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document),
6.2 创建node
    req.createNode = function(config, moduleName, url) {
        var node = config.xhtml ?
            document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') :
            document.createElement('script');
        node.type = config.scriptType || 'text/javascript';
        node.charset = 'utf-8';
        node.async = true;
        return node;
    };

传入的参数:
这个path是在main.js中定义的

require.config({
    path: {
        "a": "a",
        "b": "b"
    }
})

deps=[‘main’],应该main默认就为依赖项吧,因为之前在
这里写图片描述

createNode()就是构造一段script,而且指定了charset-set 和async(异步加载);
这里写图片描述

 node.setAttribute('data-requirecontext', context.contextName);
            node.setAttribute('data-requiremodule', moduleName);

这两句话为node添加了新的属性
这里写图片描述

为node绑定新的事件
 node.addEventListener('load', context.onScriptLoad, false);
 node.addEventListener('error', context.onScriptError, false);

加载事件和error事件都绑定为context的对象了

其实node就是script,但是require这里为它添加了两个新的属性和新的load处理事件,我觉得requireJS的精妙之处就在这里吧。

继续循环看是否有加载项

这个时候a.js并没有加载,又出现了.@r5,我猜测b.js要出来了
这里写图片描述
然而我们看到的是,removeScript(“a”),要移除a了?但是a都没有加载啊
这里写图片描述
不对,这里是要加载a.js,然而报错了,应该是因为我们debug超出了requireJS的时间。
这里写图片描述
.@r6 .@r8出现了

先写到这里,requireJS的原理确切是很复杂,经常会对一些全局变量进行修改啥的。
到这里onScriptLoad()就结束了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值