zoukankan      html  css  js  c++  java
  • 异步模块模式

    异步模块模式

    异步模块模式AMD是当请求发出后,继续其他业务逻辑,直到模块加载完成执行后续逻辑,实现模块开发中的对模块加载完成后的引用,大名鼎鼎的require.js就是以它为思想的,异步模块模式不属于一般定义的23种设计模式的范畴,而通常将其看作广义上的架构型设计模式。

    描述

    异步模块模式主要是用在浏览器环境中,浏览器环境不同于服务器环境,为了不阻塞渲染线程通常以异步的方式来加载外部Js文件,因此要使用文件中的某些模块方法必须要经历文件加载过程,而对于这种问题同步模块模式则无法适用,需要使用异步模块模式。异步模块模式不仅减少了多人开发过程中变量、方法名被覆盖的问题,而且增加了模块依赖,使开发者不必担心某些方法尚未加载或未加载完成造成的无法使用问题,异步加载部分功能也可以将更多首屏不必要的功能剥离出去,减少首屏加载成本。

    实现

    // dom.js
    F.module("./dom", function() {
        return {
            g: function(id) {
                return document.getElementById(id);
            },
            html: function(id, html) {
                if (!html) return this.g(id).innerHTML;
                else this.g(id).innerHTML = html;
            }
        }
    });
    
    // event.js
    F.module("./event", ["./dom"], function(dom) {
        return {
            on: function(id, type, fn) {
                dom.g(id)["on" + type] = fn;
            }
        }
    });
    
    <!-- demo.html -->
    <!DOCTYPE html>
    <html>
    
    <head>
        <title>异步模块模式</title>
    </head>
    
    <body>
        <div id="demo">Click Me</div>
    </body>
    <script type="text/javascript">
    (function(F) {
        const moduleCache = {};
    
        function getUrl(moduleName) {
            return String(moduleName).replace(/.js$/g, "") + ".js"
        }
    
        function loadScript(src) {
            let _script = document.createElement("script");
            _script.type = "text/javascript";
            _script.charset = "UTF-8";
            _script.async = true;
            _script.src = src;
            document.body.appendChild(_script);
        }
    
        function setModule(moduleName, params, callback) {
            let _module = null, fn = null;
            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(null, params);
            }
        }
    
        function loadModule(moduleName, callback) {
            let _module = "";
            if (moduleCache[moduleName]) {
                _module = moduleCache[moduleName];
                if (_module.status === "loaded") {
                    // 这个很重要,loadModule一定是异步的,effectiveJS 上的某一条建议有写,永远不要同步的调用异步函数,这非常重要
                    setTimeout(callback(_module.exports), 0);
                } else {
                    // 加载完成的时候调用
                    _module.onload.push(callback);
                }
            } else {
                // 第一次加载
                moduleCache[moduleName] = {
                    moduleName: moduleName,
                    status: "loading",
                    exports: null,
                    onload: [callback]
                };
                loadScript(getUrl(moduleName));
            }
        }
    
        F.module = function(...args) {
            // 获取模块构造函数(参数数组中最后一个参数成员)
            let callback = args.pop();
            // 获取依赖模块(紧邻回调函数参数,且数据类型为数组)
            let deps = (args.length && args[args.length - 1] instanceof Array) ? args.pop() : [];
            // 该模块url(模块ID)
            let url = args.length ? args.pop() : null;
            //  依赖模块序列
            let params = [];
            // 未加载的依赖模块数量统计
            let depsCount = 0;
    
            if(deps.length) {
                deps.forEach((v ,i) => {
                    // 增加未加载依赖模块数量统计
                    depsCount++;
                    // 异步加载依赖模块
                    loadModule(deps[i], function(mod) {
                        // 依赖模块序列中添加依赖模块数量统一减一
                        depsCount--;
                        params[i] = mod;
                        // 如果依赖模块全部加载
                        if(depsCount === 0) {
                            // 在模块缓存器中矫正该模块,并执行构造函数
                            setModule(url, params, callback);
                        }
                    });
                })     
            } else { // 无依赖模块,直接执行回调函数
                // 在模块缓存器中矫正该模块,并执行构造函数
                setModule(url, [], callback);
            }
        }
    
    })((() => window.F = ({}))());
    
    
    F.module(["./event", "./dom"], function(events, dom) {
        console.log(events, dom)
        events.on("demo", "click", function() {
            dom.html("demo", "success");
        })
    });
    </script>
    
    </html>
    

    每日一题

    https://github.com/WindrunnerMax/EveryDay
    

    参考

    https://www.jianshu.com/p/d71fc902051e
    https://blog.csdn.net/WuLex/article/details/107350493
    https://blog.csdn.net/a545415/article/details/77930534
    
  • 相关阅读:
    mac redis 安装及基本设置 python操作redis
    mac webstorm自动编译typescript配置
    MySQL数据库的基本操作
    python 面试基础考试题收集
    pyhon 列表的增删改查
    python 文件读取方法详解
    MAC下绕开百度网盘限速下载的方法,三步操作永久生效
    浏览器窗口输入网址后发生的一段事情(http完整请求)
    CMDB
    django适当进阶篇
  • 原文地址:https://www.cnblogs.com/WindrunnerMax/p/14262909.html
Copyright © 2011-2022 走看看