写的寥寥草草,博客园的布局怎么弄还没有研究,再保存一份草稿,日后在完善,深度研究

require.js 加载顺序

1:加载html主页,require.js文件
2:脚本执行到html中的script开始使用require.js进行模块化加载。先将文件路径加载保存在map中。在调用require()时并没有进行相应文件的加载
3:require配置,在初始化config中到底做了些什么事情呢(真正对用的初始化函数是function(deps, callback, errback, optional)这里包括了需要定义的config基本属性,回掉函数,错误处理函数,optional)
3.1确定context使用require.js中默认的定义
3.2config基本属性不是数组与字符串(在这里的数组判断挺有意思,没有使用typeof而是使用了Object.prototype.toString.call native方法):{
保存的config基本属性
如果第二个参数数组,则callback默认也是config基本属性的一项
}
3.3config基本属性中是否包含context项
3.4验证是否已经拥有该context,同样使用了Objet.prototype.hasOwnProperty.call native方法。contextName毕竟只是一个临时变量,真正最后要用的还是require.js中的刚开始声明的那些全局变量
3.5最后将config基本属性添加到context上下文本对象中的config属性中,默认的一个config包含了如上几个基本属性
                eachProp(cfg, function (value, prop) {
                    if (objs[prop]) {
                        if (!config[prop]) {
                            config[prop] = {};
                        }
                        mixin(config[prop], value, true, true);
                    } else {
                        config[prop] = value;
                    }
                });
 
    function eachProp(obj, func) {
        var prop;
        for (prop in obj) {
            if (hasProp(obj, prop)) {
                if (func(obj[prop], prop)) {
                    break;
                }
            }
        }
    }
 
    function mixin(target, source, force, deepStringMixin) {
        if (source) {
            eachProp(source, function (value, prop) {
                if (force || !hasProp(target, prop)) {
                    if (deepStringMixin && typeof value === 'object' && value &&
                        !isArray(value) && !isFunction(value) &&
                        !(value instanceof RegExp)) {
 
                        if (!target[prop]) {
                            target[prop] = {};
                        }
                        mixin(target[prop], value, force, deepStringMixin);
                    } else {
                        target[prop] = value;
                    }
                }
            });
        }
        return target;
    }
 
    function each(ary, func) {
        if (ary) {
            var i;
            for (i = 0; i < ary.length; i += 1) {
                if (ary[i] && func(ary[i], i, ary)) {
                    break;
                }
            }
        }
    }
但是在eachProp中我们也看到了,可以添加自定义属性,mixin config中 ,packages必须是数组,其他都是object对象,
3.6创建上下文对象context的equire属性。至此所有的script中的顺序动作已经完成了
            makeRequire: function (relMap, options) {
                options = options || {};
 
                function localRequire(deps, callback, errback) {
                    var id, map, requireMod;
 
                    if (options.enableBuildCallback && callback && isFunction(callback)) {
                        callback.__requireJsBuild = true;
                    }
 
                    if (typeof deps === 'string') {
                        if (isFunction(callback)) {
                            //Invalid call
                            return onError(makeError('requireargs', 'Invalid require call'), errback);
                        }
 
                        //If require|exports|module are requested, get the
                        //value for them from the special handlers. Caveat:
                        //this only works while module is being defined.
                        if (relMap && hasProp(handlers, deps)) {
                            return handlers[deps](registry[relMap.id]);
                        }
 
                        //Synchronous access to one module. If require.get is
                        //available (as in the Node adapter), prefer that.
                        if (req.get) {
                            return req.get(context, deps, relMap, localRequire);
                        }
 
                        //Normalize module name, if it contains . or ..
                        map = makeModuleMap(deps, relMap, false, true);
                        id = map.id;
 
                        if (!hasProp(defined, id)) {
                            return onError(makeError('notloaded', 'Module name "' +
                                        id +
                                        '" has not been loaded yet for context: ' +
                                        contextName +
                                        (relMap ? '' : '. Use require([])')));
                        }
                        return defined[id];
                    }
 
                    //Grab defines waiting in the global queue.
                    intakeDefines();
 
                    //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;
                }
 
                mixin(localRequire, {
                    isBrowser: isBrowser,
 
                    /**
                     * Converts a module name + .extension into an URL path.
                     * *Requires* the use of a module name. It does not support using
                     * plain URLs like nameToUrl.
                     */
                    toUrl: function (moduleNamePlusExt) {
                        var ext,
                            index = moduleNamePlusExt.lastIndexOf('.'),
                            segment = moduleNamePlusExt.split('/')[0],
                            isRelative = segment === '.' || segment === '..';
 
                        //Have a file extension alias, and it is not the
                        //dots from a relative path.
                        if (index !== -1 && (!isRelative || index > 1)) {
                            ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length);
                            moduleNamePlusExt = moduleNamePlusExt.substring(0, index);
                        }
 
                        return context.nameToUrl(normalize(moduleNamePlusExt,
                                                relMap && relMap.id, true), ext,  true);
                    },
 
                    defined: function (id) {
                        return hasProp(defined, makeModuleMap(id, relMap, false, true).id);
                    },
 
                    specified: function (id) {
                        id = makeModuleMap(id, relMap, false, true).id;
                        return hasProp(defined, id) || hasProp(registry, id);
                    }
                });
 
                //Only allow undef on top level require calls
                if (!relMap) {
                    localRequire.undef = function (id) {
                        //Bind any waiting define() calls to this context,
                        //fix for #408
                        takeGlobalQueue();
 
                        var map = makeModuleMap(id, relMap, true),
                            mod = getOwn(registry, id);
 
                        removeScript(id);
 
                        delete defined[id];
                        delete urlFetched[map.url];
                        delete undefEvents[id];
 
                        //Clean queued defines too. Go backwards
                        //in array so that the splices do not
                        //mess up the iteration.
                        eachReverse(defQueue, function(args, i) {
                            if(args[0] === id) {
                                defQueue.splice(i, 1);
                            }
                        });
 
                        if (mod) {
                            //Hold on to listeners in case the
                            //module will be attempted to be reloaded
                            //using a different config.
                            if (mod.events.defined) {
                                undefEvents[id] = mod.events;
                            }
 
                            cleanRegistry(id);
                        }
                    };
                }
 
                return localRequire;
            },
 
 
        function intakeDefines() {
            var args;
 
            //Any defined modules in the global queue, intake them now.
            takeGlobalQueue();
 
            //Make sure any remaining defQueue items get properly processed.
            while (defQueue.length) {
                args = defQueue.shift();
                if (args[0] === null) {
                    return onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + args[args.length - 1]));
                } else {
                    //args are id, deps, factory. Should be normalized by the
                    //define() function.
                    callGetModule(args);
                }
            }
        }
 
但是在require属性中有启用一个setTimeout定时间隔任务
 
    req.nextTick = typeof setTimeout !== 'undefined' ? function (fn) {
        setTimeout(fn, 4);
    } : function (fn) { fn(); };
 
        function intakeDefines() {
            var args;
 
            //Any defined modules in the global queue, intake them now.
            takeGlobalQueue();
 
            //Make sure any remaining defQueue items get properly processed.
            while (defQueue.length) {
                args = defQueue.shift();
                if (args[0] === null) {
                    return onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + args[args.length - 1]));
                } else {
                    //args are id, deps, factory. Should be normalized by the
                    //define() function.
                    callGetModule(args);
                }
            }
        }
 
        function takeGlobalQueue() {
            //Push all the globalDefQueue items into the context's defQueue
            if (globalDefQueue.length) {
                //Array splice in the values since the context code has a
                //local var ref to defQueue, so cannot just reassign the one
                //on context.
                apsp.apply(defQueue,
                           [defQueue.length, 0].concat(globalDefQueue));
                globalDefQueue = [];
            }
        }
 
获取module
        function getModule(depMap) {
            var id = depMap.id,
                mod = getOwn(registry, id);
 
            if (!mod) {
                mod = registry[id] = new context.Module(depMap);
            }
 
            return mod;
        }
经过几次循环调用后,终于load到了第一个moudle,是在makeModuleMap方法中url等信息的拼装,保存到了depMaps中。同时depCount的计数值也加一了。这也就是require.js最重要的模块化,将所有的要加载文件通过一个map对下保存,每个文件用require.js的moudle进行封装,封装了什么东西呢?
这个封装而不是单独的封装一个module对象,而是先进性了require的对象-》context对象-》module对象
 
 
 
对于module的加载过程中函数的执行顺序?
nextTick循环调用
-intakeDefines
--takeGlobalQueue
-getModule
--makeModuleMap
---splitPrefix
---normalize
----trimDots
---splitPrefix
---nameToUrl
---Module
-Module.init
--Module.enable
---Module.enable
---Module.check
---Module.emit
-checkLoaded
注意:如果通过require.js模块加载的第一个文件加载进来后,因为require.js还没有结束,DOM加载还需要继续,所以还会顺序运行新进来的文件。
 
 
check
fetch
enable

callPlugin
load 
 
跳回到context
load
跳回到require
load
最后真正实用的还是req.load加载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);
 
            //Set up load listener. Test attachEvent first because IE9 has
            //a subtle issue in its addEventListener and script onload firings
            //that do not match the behavior of all other browsers with
            //addEventListener support, which fire the onload event for a
            //script right after the script execution. See:
            //https://connect.microsoft.com/IE/feedback/details/648057/script-onload-event-is-not-fired-immediately-after-script-execution
            //UNFORTUNATELY Opera implements attachEvent but does not follow the script
            //script execution mode.
            if (node.attachEvent &&
                    //Check if node.attachEvent is artificially added by custom script or
                    //natively supported by browser
                    //read https://github.com/jrburke/requirejs/issues/187
                    //if we can NOT find [native code] then it must NOT natively supported.
                    //in IE8, node.attachEvent does not have toString()
                    //Note the test for "[native code" with no closing brace, see:
                    //https://github.com/jrburke/requirejs/issues/273
                    !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) &&
                    !isOpera) {
                //Probably IE. IE (at least 6-8) do not fire
                //script onload right after executing the script, so
                //we cannot tie the anonymous define call to a name.
                //However, IE reports the script as being in 'interactive'
                //readyState at the time of the define call.
                useInteractive = true;
 
                node.attachEvent('onreadystatechange', context.onScriptLoad);
                //It would be great to add an error handler here to catch
                //404s in IE9+. However, onreadystatechange will fire before
                //the error handler, so that does not help. If addEventListener
                //is used, then IE will fire error before load, but we cannot
                //use that pathway given the connect.microsoft.com issue
                //mentioned above about not doing the 'script execute,
                //then fire the script load event listener before execute
                //next script' that other browsers do.
                //Best hope: IE10 fixes the issues,
                //and then destroys all installs of IE 6-9.
                //node.attachEvent('onerror', context.onScriptError);
            } else {
                node.addEventListener('load', context.onScriptLoad, false);
                node.addEventListener('error', context.onScriptError, false);
            }
            node.src = url;
 
            //For some cache cases in IE 6-8, the script executes before the end
            //of the appendChild execution, so to tie an anonymous define
            //call to the module name (which is stored on the node), hold on
            //to a reference to this node, but clear after the DOM insertion.
            currentlyAddingScript = node;
            if (baseElement) {
                head.insertBefore(node, baseElement);
            } else {
                head.appendChild(node);
            }
            currentlyAddingScript = null;
 
            return node;
        } else if (isWebWorker) {
            try {
                //In a web worker, use importScripts. This is not a very
                //efficient use of importScripts, importScripts will block until
                //its script is downloaded and evaluated. However, if web workers
                //are in play, the expectation that a build has been done so that
                //only one script needs to be loaded anyway. This may need to be
                //reevaluated if other use cases become common.
                importScripts(url);
 
                //Account for anonymous modules
                context.completeLoad(moduleName);
            } catch (e) {
                context.onError(makeError('importscripts',
                                'importScripts failed for ' +
                                    moduleName + ' at ' + url,
                                e,
                                [moduleName]));
            }
        }
    };
 
创建一个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;
    };
继续组装script node 
head = s.head = document.getElementsByTagName('head')[0];
在这里require.Js将script node添加到了原始html中的head标签内
新生成的head,同时浏览器也对js文件进行了加载
 
最后有意思的是require.js在checkLoaded时竟然做了一遍remove,这个还是蛮有意思的,
 

require.js源码分析的更多相关文章

  1. Require.js 源码分析

    本文将简单介绍下个人对require.js的源码分析,简单分析实现原理 一.require加载资源的流程 require中,根据AMD(Asynchronous Module Definition)的 ...

  2. basket.js 源码分析

    basket.js 源码分析 一.前言 basket.js 可以用来加载js脚本并且保存到 LocalStorage 上,使我们可以更加精准地控制缓存,即使是在 http 缓存过期之后也可以使用.因此 ...

  3. events.js 源码分析

    events.js 源码分析 1. 初始化 // 使用 this.ee = new EventEmitter(); // 源码 // 绑定this域,初始化 _events,_eventsCount和 ...

  4. Backbone.js源码分析(珍藏版)

    源码分析珍藏,方便下次阅读! // Backbone.js 0.9.2 // (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc. // Backbone ...

  5. Vue.js 源码分析(二十七) 高级应用 异步组件 详解

    当我们的项目足够大,使用的组件就会很多,此时如果一次性加载所有的组件是比较花费时间的.一开始就把所有的组件都加载是没必要的一笔开销,此时可以用异步组件来优化一下. 异步组件简单的说就是只有等到在页面里 ...

  6. Vue.js 源码分析(三十一) 高级应用 keep-alive 组件 详解

    当使用is特性切换不同的组件时,每次都会重新生成组件Vue实例并生成对应的VNode进行渲染,这样是比较花费性能的,而且切换重新显示时数据又会初始化,例如: <!DOCTYPE html> ...

  7. Vue.js 源码分析(三十) 高级应用 函数式组件 详解

    函数式组件比较特殊,也非常的灵活,它可以根据传入该组件的内容动态的渲染成任意想要的节点,在一些比较复杂的高级组件里用到,比如Vue-router里的<router-view>组件就是一个函 ...

  8. Vue.js 源码分析(二十九) 高级应用 transition-group组件 详解

    对于过度动画如果要同时渲染整个列表时,可以使用transition-group组件. transition-group组件的props和transition组件类似,不同点是transition-gr ...

  9. Vue.js 源码分析(二十八) 高级应用 transition组件 详解

    transition组件可以给任何元素和组件添加进入/离开过渡,但只能给单个组件实行过渡效果(多个元素可以用transition-group组件,下一节再讲),调用该内置组件时,可以传入如下特性: n ...

随机推荐

  1. Java里面获取当前服务器的IP地址

    public static void main(String[] args) { try { InetAddress address = InetAddress.getLocalHost();//获取 ...

  2. angular 路由请求js文件

    <script type="text/javascript" src="http://apps.bdimg.com/libs/angular.js/1.3.2/an ...

  3. 2017 New Year’s Greetings from Sun Yat-sen University

    As winter turns to spring, the world around us begins to take on an air of freshness. As  2017 is fa ...

  4. 编译2.4.X apache 常见错误

    安装高版本的 apr    apr-util ./configure prefix=/usr/local/apr   ./configure prefix=/usr/local/apr-util -- ...

  5. openssl evp RSA 加密解密

    openssl evp RSA 加密解密 可以直接使用RSA.h 提供的接口 如下测试使用EVP提供的RSA接口 1. EVP提供的RSA 加密解密 主要接口: int EVP_PKEY_encryp ...

  6. Java中的方法应用

    一.如何定义java中的方法 所谓方法,就是用来解决一类问题的代码的有序组合,是一个功能模块. 语法: 1. 访问修饰符:方法允许被访问的权限范围, 可以是 public.protected.priv ...

  7. Mybatis + Mysql 插入数据时中文乱码问题

    近日跟朋友一起建立一个项目,用的是spring+mybatis+mysql. 今天碰到一个mybatis向mysql中插入数据时,中文显示为'???'的问题,拿出来说下. 对于数据库操作中出现的中文乱 ...

  8. Elasticsearch5.0.1 + Kibana5.0.1 + IK 5.0.1安装记录

    最近工作需要,开始研究ES,当前ES的最新版本为5.0.1,从之前的2.x的版本号一下升级到5.x,主要是之前Elastic的产品版本号因为收购等原因很乱,ES 2.X版本的和Kibana 4.x版本 ...

  9. 获取Mac地址

    netapi32.lib#include <NB30.h>; typedef struct _ASTAT_ { ADAPTER_STATUS adapt; NAME_BUFFER Name ...

  10. SharePoint 根据时间筛选

    最近在整SP列表 老大要求用列表规范周报格式. 提出要在一个视图内查看上周一至周日的内容 翻了下资料想到了以下几种方法 1.在视图页面添加时间筛选器webpart,用参数传入列表筛选 2.在列表添加按 ...