requirejs异步加载js文件流程

这篇文章基于requirejs-2.1.11来分析其加载js文件的流程,而对requirejs其他相关内容不做过多探讨,如有其他方面的需求可参考其规范:http://www.requirejs.cn/或者自行阅读源码。

一般使用requirejs加载js文件有以下两种方法,一种是定义data-main,另一种使用define或require方法来加载。如下所示,使用define方法,传入的第一个参数是我们要加载的依赖,而第二个参数是当所有依赖加载完毕后进行的回调,当然,如果不是定义模块用require即可。先分析第一种然后在详细考察第二种加载方法,估计这两者大同小异。

<script data-main="app.js" src="../lib/require/require-2.1.11.js"></script>

define(["angularAMD"], function(angularAMD) {
  ...
}

当requirejs加载完毕后会执行一个立即执行的函数,并且会执行下面这段代码:

if (isBrowser && !cfg.skipDataMain) {
        //Figure out baseUrl. Get it from the script tag with require.js in it.
        eachReverse(scripts(), function (script) {
            //Set the 'head' where we can append children by
            //using the script's parent.
            if (!head) {
                head = script.parentNode;
            }

            //Look for a data-main attribute to set main script for the page
            //to load. If it is there, the path to data main becomes the
            //baseUrl, if it is not already set.
            dataMain = script.getAttribute('data-main');
            if (dataMain) {
                //Preserve dataMain in case it is a path (i.e. contains '?')
                mainScript = dataMain;

                //Set final baseUrl if there is not already an explicit one.
                if (!cfg.baseUrl) {
                    //Pull off the directory of data-main for use as the
                    //baseUrl.
                    src = mainScript.split('/');
                    mainScript = src.pop();
                    subPath = src.length ? src.join('/')  + '/' : './';

                    cfg.baseUrl = subPath;
                }

                //Strip off any trailing .js since mainScript is now
                //like a module name.
                mainScript = mainScript.replace(jsSuffixRegExp, '');

                 //If mainScript is still a path, fall back to dataMain
                if (req.jsExtRegExp.test(mainScript)) {
                    mainScript = dataMain;
                }

                //Put the data-main script in the files to load.
                cfg.deps = cfg.deps ? cfg.deps.concat(mainScript) : [mainScript];

                return true;
            }
        });
    }

这段代码的主要功能是解析script标签,找出标签中的data-main属性,并且限制最多只找出一个,然后将值也就是要加载的js文件添加到将要下载的任务列表中。下面详细说说其中的逻辑。

isBrowser的定义为 isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document) ,默认情况下为true。

cfg为一个存储配置信息的对象,在执行这段代码之前会检查全局变量requirejs和require是否不为空且为对象,如果是就将他们赋给cfg。所以如若需要配置,只需在执行requirejs之前设置require或requirejs这两个变量即可。这里默认为null,于是就执行到方法内部了。

eachReverse(ary, func)的作用是将func依次作用于第一个参数数组中的每一个元素,如果func返回true则跳出循环,上面这段代码返回的是true,因此只会执行一次。

scripts()即获取当前页面tag为script的元素,返回一个数组,接下来将按照上面所述依次处理这个数组中的元素。

变量head在后面加载js文件时有用,将要加载的js文件以script标签的形式添加到head的子节点中即可。这里如果head未定义,则将当前script的父节点赋给head。

取出'data-main'属性dataMain,在我们的例子中就是'app.js'。根据dataMain设置cfg.baseUrl,这个baseUrl和dataMain在同一目录下。举例,如果dataMain='app.js',那么baseUrl='./',如果dataMain='js/main/app.js',那么baseUrl='js/main/',总之和app.js为同一目录。【有何用?】

然后去掉.js这个后缀。【后面会添加上吗?】

然后通过req.jsExtRegExp.test(mainScript)来判断mainScript是否仍然是个路径,即mainScript中是否包含其中的模式,如果是则将原始路径dataMain赋给mainScript。jsExtRegExp=/^\/|:|\?|\.js$/,其含义如下:【什么样的正常情况会执行这里?】

 最后将mainScript添加到cfg.deps这个数组中,接下来看如何处理这个数组中的数据。

    req = requirejs = function (deps, callback, errback, optional) {

        //Find the right context, use default
        var context, config,
            contextName = defContextName;

        // Determine if have config object in the call.
        if (!isArray(deps) && typeof deps !== 'string') {
            // deps is a config object
            config = deps;
            if (isArray(callback)) {
                // Adjust args if there are dependencies
                deps = callback;
                callback = errback;
                errback = optional;
            } else {
                deps = [];
            }
        }

        if (config && config.context) {
            contextName = config.context;
        }

        context = getOwn(contexts, contextName);
        if (!context) {
            context = contexts[contextName] = req.s.newContext(contextName);
        }

        if (config) {
            context.configure(config);
        }

        return context.require(deps, callback, errback);
    };

 

转载于:https://www.cnblogs.com/withparadox2/p/5661725.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值