设计模式知识连载(46)---异步模块模式:

<body>


<h3>设计模式知识连载(46)---异步模块模式:</h3>
<div>
    <p>
        模块化:将复杂的系统分解成高内聚、低耦合的模块,使系统开发变得可控、可维护、可拓展,提高模块的复用率
    </p>
    <p>
        请求发出后,继续其他业务逻辑,知道模块加载完成执行后续的逻辑,实现模块开发中对模块加载完成后的引用
    </p>
</div>


<hr>



<script type="text/javascript">



    /**
    *   案例一:异步加载文件中的模块,方式一:初始
    */
    // // 加载脚本文件
    // var loadScript = function(src) {
    //  // 创建脚本元素
    //  var _script = document.createElement('script') ;
    //  // 设置类型
    //  _script.type = 'text/javascript' ;
    //  // 设置加载路径
    //  _script.src = src ;
    //  //将元素插入到页面中
    //  document.getElementsByTagName('head')[0].appendChild(_script) ;
    // }
    // // 加载localstorage文件
    // loadScript('localstorage.js') ;
    // // 使用localstorage模块
    // F.module('localstorage', function(ls) {
    //  // do something
    // }) ;

    /**
    *   案例一:异步加载文件中的模块,方式二:进阶
    */

    /**
    *   闭包环境 
    **/
    // 向闭包中传入模块管理其对象F(~屏蔽雅素偶文件时,前面漏写;报错) 
    ~(function(F) {
        // 模块缓存器。存储已创建模块
        var moduleCache = {} ;
    }) ((function() {
        // 创建模块管理器对象F,并保存在全局作用域中
        return window.F = {} ;
    }) ()) ;

    /**
    *   创建或调用模块方法
    *   @param  url             参数为模块URL
    *   @param  deps            参数为依赖模块 
    *   @param  callback        参数为模块主函数
    **/
    F.module = function(url, modDeps, modCallback) {
        // 将参数转化为数组
        var args = [].slice.call(arguments) ;
        // 获取模块构造函数(参数数组中最后一个参数成员)
        var callback = args.pop() ;
        // 获取依赖模块(紧邻回调函数参数,且数据类型为数组)
        var deps = (args.length && args[args.length - 1] instanceof Array) ? args.pop() : [] ; 
        // 该模块URL(模块ID)
        var url = args.length ? args.pop() : null ;
        // 依赖模块序列
        var params = [] ;
        // 未加载的依赖模块数量统计
        var depsCount = 0 ;
        // 依赖模块序列中索引值
        var i = 0 ;
        // 依赖模块序列长度
        var len ;
        // 获取依赖模块长度
        if(len = deps.length) {
            // 遍历依赖模块
            while(i < len) {
                // 闭包保存i
                (function(i) {
                    // 增加未加载依赖模块数量统计
                    depsCount++ ;
                    // 异步加载依赖模块
                    loadModule(deps[i], function(mod) {
                        // 依赖模块序列中添加依赖模块接口引用
                        params[i] = mod ;
                        // 依赖模块加载完成,依赖模块数量统计减一
                        depsCount-- ;
                        // 如果依赖模块全部加载
                        if(depsCount === 0) {
                            // 在模块缓存器中矫正该模块,并执行构造函数
                            setModule(url, params, callback) ;
                        }
                    }) ;
                }) (i) ;
                // 遍历下一依赖模块
                i++ ;
            }
        // 无依赖模块,直接执行回调函数   
        }else {
            // 在模块缓存器中矫正该模块,并执行构造函数
            setModule(url, [], callback) ;
        }
    }

    // 加载模块
    var moduleCache = {} ;

    /***
    *   异步加载依赖模块所在文件
    *   @param      moduleName      模块路径(id)
    *   @param      callback        模块加载完成回调函数
    **/
    var loadModule = function(moduleName, callback) {
        // 依赖模块
        var _module ;
        // 如果依赖模块被要求加载过
        if(moduleCache[moduleName] {
            // 获取该模块信息
            _module = moduleCache[moduleName] ;
            // 如果模块加载完成
            if(_module.status === 'loaded') {
                // 执行模块加载完成回调函数
                setTimeout(callback(_module.exports), 0) ;
            }else {
                // 缓存该模块所处文件加载完成回调函数
                _module.onload.push(callback) ;
            }
        // 模块第一次被依赖引用   
        }else {
            // 缓存该模块初始化信息
            moduleCache[moduleName] = {

                moduleName : moduleName,        // 模块id
                status : 'loading',             // 模块对应文件加载状态(默认加载中)
                exports : null,                 // 模块接口
                onload : [callback]             // 模块对应文件加载完成回调函数缓冲器
            };
            // 加载模块对应文件
            loadScript(getUrl(moduleName)) ;
        }
    } ;
    // 获取文件路径
    var getUrl = function(moduleName) {
        // 拼接完整的文件路径字符串,如'lib/ajas' => 'lib/ajax.js'
        return String(moduleName).replace(/\.js$/g, '') + '.js' ;
    } ;
    // 加载脚本文件
    var loadScript = function(src) {
        var _script = document.createElement('script') ;
        // 文本类型
        _script.type = 'text/JavaScript' ;
        // 确认编码
        _script.charset = 'UTF-8' ;
        // 异步加载
        _script.async = true ;
        // 文件路径
        _script.src = src ;
        // 插入页面中
        document.getElementsByTagName('head')[0],appendChild(_script) ;
    };

    /***
    *   设置模块并执行模块构造函数
    *   @param   moduleName         模块id名称
    *   @param   params             依赖模块
    *   @param   callback           模块构造函数
    **/ 
    var setModule = function(moduleName, params, callback) {
        // 模块容器,模块文件加载完成回调函数
        var _module, fn ;
        // 如果模块被调用过
        if(moduleCache[moduleName]) {
            // 获取模块
            _module = moduleCache[moduleName] ;
            // 设置模块已经加载完成
            _module.status = 'loaded' ;
            // 矫正模块接口
            _module.exports = callback ? callback.apply(_module, params) : null ;
            // 执行模块文件加载完成回调函数
            while(fn = _module.onload.shift()) {
                fn(_module.exports) ;
            }
        }else {
            // 模块不存在(匿名函数),则直接执行构造函数
            callback && callback.apply(nulll, params) ;
        }
    };

    /******测试用例****************************************************/
    // 在lib/dom.js中定义dom模块
    F.module('lib/dom', function() {
        return {
            // 获取元素方法
            g : function(id) {
                return document.getElementById(id) ;
            },
            // 获取或者设置元素内容方法
            html : function(id, html) {
                if(html) {
                    this.g(id).innerHTML = html ;
                }else {
                    return this.g(id).innerHTML ;
                }
            }
        }
    }) ;

    // 在lib/event.js文件中定义event模块
    F.module('lib/event', ['lib/dom'], function(dom) {
        var events = {
            // 绑定事件
            on : function(id, type, fn) {
                dom : g(id)['on' + type] = fn ;
            }
        } ;
        return events
    }) ;

    // 在页面中引用dom模块与event模块,为页面中的button绑定事件,添加交互。【index.html页面】
    F.module(['lib/event', 'lib/dom'], function(events, dom) {
        events.on('demo', 'click', function() {
            dom.html('demo', 'success') ;
        }) ;
    }) ;
</script>    

</body>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值