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模块")
});

文件目录图

加载顺序图

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

查看全文
  • 相关阅读:
    搭建非域AlwaysOn win2016+SQL2016
    从0开始搭建SQL Server AlwaysOn 第四篇(配置异地机房节点)
    从0开始搭建SQL Server AlwaysOn 第二篇(配置故障转移集群)
    从0开始搭建SQL Server AlwaysOn 第三篇(配置AlwaysOn)
    从0开始搭建SQL Server AlwaysOn 第一篇(配置域控)
    四、基于Windows 2012配置SQL Server 2014 AlwaysOn
    三、安装SQLserver 2014(For AlwaysOn)
    二、 Windows 2012配置故障转移(For SQLServer 2014 AlwaysOn)
    Mybatis-SQL语句构建器类及日志
    Mybatis-JavaAPI
  • 原文地址:https://www.cnblogs.com/rubylouvre/p/1951104.html
  • Copyright © 2011-2022 走看看