zoukankan      html  css  js  c++  java
  • 我的模块加载系统 v3

    近一年来,外国非常热衷异步加载的研究。为了加快页面的载入速度,无阻塞的动态script注入的应用重新回到舞台的中心。LAB.jsControlJS ,Head JS, yepnopejs, $script.js,NBL JohnnyDepp.js loadrunner还有基于jquery的RequireJS,嘛,它已是另一个层面的东西,还搞了一个术语AMD(Modules/AsynchronousDefinition)来唬人。国内的,暂时只有岁月如歌的 SeaJS 比较有名。说是顺应潮流也好,跟风凑热闹也好,我也升级了我的模块加载系统,取名为并行加载器,作为我的框架的核心模块而存在。

    为方便起见,用定时器进行哈希检测代替本来需要的script回调函数验证。require,declare与provide这些方法名听岁月如歌说的某一套标准制定的东西。嘛,我单是觉得名字好用借来用用,并不遵循它的条规行事的。

    下面是它的一些API介绍:

    dom.require(dependList,callback):请求模块。
     
    dependList为依赖列队,可以为字符串或数组。如果在字符串状态下表示多个模块,请用逗号隔开。如果依赖模块的JS文件与核心模块的JS文件不在同一个文件夹下,可以使用“/”隔开,或者后面用小括号指定具体路径,亦即"path/path/moduleName(url),path/path/moduleName(url)"的格式,可以简化为"moduleName(url)", "path/path/moduleName"。moduleName可以包含"."号。callback为回调函数,没有什么好说的。
     
    dom.provide(array,hash,callback):提供模块。
     
    array为数组,里面为经过处理的模块名,换言之,不再包含path或url。hash,用于注册与验证模块名,标识这个模块已经加载过了。callback为回调函数。
     
    dom.declare(moduleName,dependList,callback):声明模块。
     
    此方法只是dom.require方法的一个简单封简而已,用于保证其回调函数在依赖模块都加载的情况下安全执行。moduleName为模块名,不能有path与url,dependList、callback这两个参数与dom.require相同。

作为约定,模块名应该与其所在的JS文件名相同,但也允许不一样(到时请用小括号指定具体路径),一个JS文件也可以放置多个模块,这时我抛弃使用script.onload与script.onreadystatechange来验证模块加载成功的原因,它们只在移除script节点本身时发挥效力。

王婆卖瓜,自吹一下优点:

  1. 按需加载
  2. 无阻塞
  3. 实现JS颗粒化管理
  4. 解决Ajax无法处理的跨域问题
  5. 模块自动处理依赖
  6. 以后还考虑文件合并的问题
;;;(function(WIN,DOM,undefined){
    var
    reg_module_name = /(?:^|\/)([^(\/]+)(?=\(|$)/,
    reg_module_url = /\(([^)]+)\)/,
    reg_multi_module = /\s*,\s*/g,
    _dom = WIN.dom,
    dom = {
        mix : function(target, source ,override) {
            var i, ride = (override === void 0) || override;
            for (i in source) {
                if (ride || !(i in target)) {
                    target[i] = source[i];
                }
            }
            return target;
        },
 
        noConflict: function(  ) {//防止命名冲突,请先行引用其他库再引用本框架
            WIN.dom = _dom;//这是别人的
            return dom;//请赋以其一个命名空间
        },
        //请求模块
        require:function(dependList,callback){
            var self = arguments.callee
            var moduleNames = [], i =0, hash = self.loadedModules,
               re = reg_multi_module, reg = reg_module_name ,moduleName, str;
            if(typeof dependList === "string"){
                dependList  = dependList.split(re)
            }
            while(str = dependList[i++]){
                moduleName = str.match(reg)[1];
                if(!hash[moduleName]){
                    moduleNames.push(moduleName);
                    self.appendScript(str);
                }
            }
            this.provide(moduleNames,hash,callback)
        },
        //声明模块
        declare:function(moduleName,dependList,callback){
            var hash = this.require.loadedModules;
            this.require(dependList,function(){
                callback();
                hash[moduleName] = 1
            })
        },
        //提供模块
        provide:function(array,hash,callback){
            var flag = true, i = 0, args = arguments, fn = args.callee, el;
            while(el = array[i++]){
                if(!hash[el]){
                    flag = false;
                    break;
                }
            }
            if(flag){
                callback();
            }else{
                //javascrpt最短时钟间隔为16ms,这里取其倍数
                //http://blog.csdn.net/aimingoo/archive/2006/12/21/1451556.aspx
                setTimeout(function(){
                    fn.apply(null,args)
                },32);
            }
        }
    }
    dom.mix(dom.require, {
        loadedModules:{},
        requestedUrl: {},
        //http://www.cnblogs.com/rubylouvre/archive/2011/02/10/1950940.html
        getBasePath:function(){
            var url;
            try{
                a.b.c()
            }catch(e){
                url = e.fileName || e.sourceURL;//针对firefox与safari
            }
            if(!url){
                var script = (function (e) {
                    if(!e) return null;
                    if(e.nodeName.toLowerCase() == 'script') return e;
                    return arguments.callee(e.lastChild)
                })(DOM);//取得核心模块所在的script标签
                url = script.hasAttribute ?  script.src : script.getAttribute('src', 4);
            }
            url = url.substr( 0, url.lastIndexOf('/'));
            dom.require.getBasePath = function(){
                return url;//缓存结果,第一次之后直接返回,再不用计算
            }
            return url;
        },
        appendScript:function(str){
            var module = str, reg = reg_module_url, url;
            //处理dom.node(http://www.cnblogs.com/rubylouvre/dom/node.js)的情形
            var _u = module.match(reg);
            url = _u && _u[1] ? _u[1] : this.getBasePath()+"/"+ str + ".js";
            if(!this.requestedUrl[url]){
                 this.requestedUrl[url] = 1;
                 var script = DOM.createElement("script");
                 script.charset = "utf-8";
                 script.defer = true;
             //  script.async = true;//不能保证多个script标签的执行顺序
                script.src = url;
            //避开IE6的base标签bug
            //http://www.cnblogs.com/rubylouvre/archive/2010/05/18/1738034.html
                DOM.documentElement.firstChild.insertBefore(script,null);//
                this.removeScript(script);  
            }
            
        },
        removeScript:function(script){//移除临时生成的节点
            var parent = script.parentNode;
            if(parent&&parent.nodeType === 1){
                script.onload = script.onreadystatechange = function(){
                    if (-[1,] || this.readyState === "loaded" || this.readyState === "complete" ){
                        if (this.clearAttributes) {
                            this.clearAttributes();
                        } else {
                            this.onload = this.onreadystatechange = null;
                        }
                        parent.removeChild(this)
                    }
                }
            }
        }
    });
    //先行取得核心模块的URL
    dom.require.getBasePath();
    window.dom = dom;
})(this,this.document);

示例:

<!doctype html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>并行加载器 by 司徒正美</title>
        <script src="dom.js"></script>
        <script>
            dom.require("dom/string,dom/array",function(){
                window.console && window.console.log("这是回调函数")
                dom.query("调用子模块的方法")
            });

        </script>
    </head>
    <body>
        <h1>并行加载器 by 司徒正美</h1>
        <p>请用FF的firebug观察效果</p>
    </body>
</html>

其他依赖模块的内容:

//string.js
dom.declare("string","dom/query",function(){
    window.console && window.console.log("已加载string模块");
});

//array.js
dom.declare("array","dom/node",function(){
    window.console && window.console.log("已加载array模块")
});
//query.js
dom.declare("query",[],function(){
    window.console && window.console.log("已加载query模块")
    dom.query = function(str){
        window.console && window.console.log(str)
    }
});
//node.js
dom.declare("node",[],function(){
    window.console && window.console.log("已加载node模块")
});

文件目录图

加载顺序图

如果对它有兴趣,可在点此下载看一下。

查看全文
  • 相关阅读:
    STM32 F4 DAC DMA Waveform Generator
    STM32 F4 General-purpose Timers for Periodic Interrupts
    Python第十四天 序列化 pickle模块 cPickle模块 JSON模块 API的两种格式
    Python第十三天 django 1.6 导入模板 定义数据模型 访问数据库 GET和POST方法 SimpleCMDB项目 urllib模块 urllib2模块 httplib模块 django和web服务器整合 wsgi模块 gunicorn模块
    查看SQL Server服务运行帐户和SQL Server的所有注册表项
    Pycharm使用技巧(转载)
    SQL Server 2014内存优化表的使用场景
    Python第十天 print >> f,和fd.write()的区别 stdout的buffer 标准输入 标准输出 从控制台重定向到文件 标准错误 重定向 输出流和输入流 捕获sys.exit()调用 optparse argparse
    Python第七天 函数 函数参数 函数里的变量 函数返回值 多类型传值 函数递归调用 匿名函数 内置函数
    Python第六天 类型转换
  • 原文地址:https://www.cnblogs.com/rubylouvre/p/1951104.html
  • Copyright © 2011-2022 走看看