同步模块模式SMD
是请求发出后,不管模块是否存在,当即执行后续的逻辑,实现模块开发中对模块的当即引用,模块化是将复杂的系统分解为高内聚、低耦合模块,同步模块模式不属于通常定义的23
种设计模式的范畴,而一般将其看做广义上的架构型设计模式。javascript
同步模块模式一般用来解决以下场景的问题,随着页面功能的增长,系统的业务逻辑愈来愈复杂,多人开发的功能常常耦合在一块儿,有时项目经理提出的需求,分配给多人实现的时候,经常由于某一处功能耦合了多人的代码,从而出现排队修改的现象。
经过使用模块化来分解复杂的系统能够很好的去解决这个问题,要想实现模块化开发,首先就须要有一个模块管理器,其管理着模块的建立与调度,对于模块的调用分为两类,第一类就是同步的模块调度,实现相对比较简单,不须要考虑模块间的异步加载,第二类的异步模块调度就比较繁琐,其能够实现对模块的加载调度。java
// 定义模块管理器单体对象 var F = F || {}; // 建立模块的方法define // str 模块路由; fn 模块方法 F.define = function(str, fn){ // 定义模块方法,本应该在闭包中定义,这里先忽略 let parts = str.split("."); // 解析模块路由str // 若是在闭包中,为了屏蔽对模块的直接访问,建议将模块添加给闭包内部私有变量 // old,当前模块的祖父模块;parent,当前模块父模块 let old = this; let parent = this; // i模块层级,len模块层级长度 let i = 0; // 若是第一个模块是模块管理器单体对象,则移除 if(parts[0] === "F") parts = parts.slice(1); // 屏蔽对define与module模块方法的重写 if(parts[0] === "define" || parts[0] === "module") return void 0; // 遍历路由器并定义每层模块 for(let len = parts.length; i < len; i++){ // 若是父模块中不存在当前模块,声明当前模块 if(parent[parts[i]] === void 0) parent[parts[i]] = {}; // 缓存下一级的祖父模块 old = parent; // 缓存下一级的父模块 parent = parent[parts[i]]; } // 若是给定模块方法fn则定义改模块方法 if(fn){ // 此时i等于parts.length,故减1 old[parts[--i]] = fn(); } return this; // 返回模块管理器单体对象 } // 用上面的方法来建立模块 // 建立模块k,并对该模块提供t方法 F.define("k", function(){ return { t: function(){ console.log("it is function t") } } //也能够以构造函数的方法返回 /* let xx = function(){}; xx.t = function(){ console.log("this is xx.t") } xx.tt = function(){ console.log("this is xx.tt") } return xx; */ }); // 使用t方法,但正式的模块开发不容许直接调用 // 一是由于模块一般为闭包中的私有变量,不会保存在F上,获取不到,这里简化没有使用闭包 // 二是由于这样调用不符合模块开发规范 F.k.t(); // 用构造函数返回时的调用方法 /* F.k.t(); F.k.tt(); */ // 也可先声明模块再定义方法 F.define("a.b") F.a.b = function(){ console.log("this is function from a.b") } F.a.b(); // 因为不能直接调用,就须要调用模块的方法 // 调用模块的方法module // 参数分两部分,依赖模块与回调函数(最后一个参数) // 原理是遍历获取全部依赖模块,并保存在依赖模块列表中,而后将这些依赖模块做为参数传入执行函数中执行 F.module = function(...args){ let fn = args.pop(); // 获取回调执行函数 // 获取依赖模块,若args[0]是数组,则它为依赖模块,不然为args let parts = args[0] && args[0] instanceof Array ? args[0] : args; let modules = []; // 依赖模块列表 let modIDs = ""; // 模块路由 let i = 0; // 依赖模块索引 let ilen = parts.length; // 依赖模块长度 // 遍历依赖模块 parts.forEach(v => { if(typeof v === "string"){ // 若是是模块路由 let parent = this; // 设置当前模块父对象(F) // 解析模块路由,并屏蔽掉模块父对象 modIDs = v.replace(/^F./, "").split("."); // 遍历模块路由层级 for(let j = 0; j < modIDs.length; j++){ parent = parent[modIDs[j]] || false; // 重置父模块 } modules.push(parent); // 将模块添加到模块依赖列表 }else{ // 若是是模块对象 modules.push(v); // 直接加入模块依赖列表 } }) fn.apply(null, modules); // 执行回调函数 } // 依赖dom和k模块的方法,数组形式 F.module(["dom", "k"], function(){ console.log(1); }) // 依赖dom2模块和k.a方法,字符串形式 F.module("dom2", "k.a", function(){ console.log(2); })
https://github.com/WindrunnerMax/EveryDay
https://www.jianshu.com/p/2359390737aa https://www.dazhuanlan.com/2020/03/09/5e65fa05c9bb7/ https://blog.csdn.net/WuLex/article/details/107350493