同步模塊模式

同步模塊模式

同步模塊模式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
相關文章
相關標籤/搜索