Synchronous Module Pattern

The Synchronous Module Pattern SMD is the immediate execution of subsequent logic regardless of whether the module exists or not, enabling immediate referencing to the module in module development. Modularization involves breaking down complex systems into highly cohesive, loosely coupled modules. The Synchronous Module Pattern does not belong to the conventional definition of the 23 design patterns, but is generally considered as a broad architectural design pattern.

Description

The Synchronous Module Pattern is typically used to address the following scenario: as the functionality of a page increases, the business logic of the system becomes more complex. Features developed by multiple people often end up being coupled together. Sometimes, when the project manager assigns a requirement to be implemented by multiple people, it often leads to a queue for modification due to certain functionalities being coupled with the code of multiple individuals.
By using modularization to break down complex systems, this problem can be effectively addressed. In order to achieve modular development, a module manager is needed to manage the creation and scheduling of modules. Module calls are divided into two categories: the first category is synchronous module scheduling, which is relatively simple to implement and does not require consideration of asynchronous module loading. The second category, asynchronous module scheduling, is more complicated and can handle module loading scheduling.

Implementation

// Define the module manager singleton object
var F = F || {};
// Create the module method define
// str, module route; fn, module method
F.define = function(str, fn){   // Define the module method, which should be defined in a closure, but let's ignore that for now
    let parts = str.split("."); // Parse the module route str
    // If inside a closure, to shield direct access to the module, it is recommended to add the module to a private variable within the closure
    // old, the current module's parent module; parent, the current module's parent module
    let old = this;
    let parent = this;
    // i module level; len module level length
    let i = 0;
    // If the first module is the module manager singleton object, remove it
    if(parts[0] === "F") parts = parts.slice(1);
    // Shield the rewriting of the define and module module methods
    if(parts[0] === "define" || parts[0] === "module") return void 0;
    // Traverse the route and define each level of the module
    for(let len = parts.length; i < len; i++){
        // If the current module does not exist in the parent module, declare the current module
        if(parent[parts[i]] === void 0) parent[parts[i]] = {};
        // Cache the next level's parent module
        old = parent;
        // Cache the next level's grandparent module
        parent = parent[parts[i]];
    }
    // If the module method fn is given, define the module method
    if(fn){
        // At this point, i is equal to parts.length, so subtract 1
        old[parts[--i]] = fn();
    }
    return this;    // Return the module manager singleton object
}

// Use the above method to create modules
// Create module k and provide the method t to the module
F.define("k", function(){
    return {
        t: function(){
            console.log("it is function t")
        }
    }
    // It can also be returned using a constructor function
    /* let xx = function(){};
    xx.t = function(){
        console.log("this is xx.t")
    }
    xx.tt = function(){
        console.log("this is xx.tt")
    }
    return xx; */
});

// Use the t method, but directly calling it in formal module development is not allowed
// First, because modules are usually private variables in closures and are not stored in F, so they cannot be accessed. This simplification is not using a closure
// Second, because calling it this way does not comply with module development standards
F.k.t();
// Call method when returning with a constructor function
/* F.k.t();
F.k.tt(); */

// Modules can also be declared first and then methods defined
F.define("a.b")
F.a.b = function(){
    console.log("this is function from a.b")
}
F.a.b();
// Since you can't directly call it, you need to call the module's method
// Call the module's method module
// The parameters are divided into two parts, the dependent module and the callback function (the last parameter)
// The principle is to iterate through all dependent modules, save them in the list of dependent modules, and then pass these dependent modules as parameters to the execution function to execute
F.module = function(...args){
    let fn = args.pop();    // Get the callback execution function
    // Get dependent modules, if args[0] is an array, it is the dependent module, otherwise it is args
    let parts = args[0] && args[0] instanceof Array ? args[0] : args;
    let modules = [];   // List of dependent modules
    let modIDs = "";    // Module route
    let i = 0;  // Dependent module index
    let ilen = parts.length;    // Dependent module length
    // Iterate through dependent modules
    parts.forEach(v => {
        if(typeof v === "string"){   // If it is a module route
            let parent = this;  // Set the current module parent object (F)
            // Parse the module route and shield the module parent object
            modIDs = v.replace(/^F./, "").split(".");
            // Iterate through the module route levels
            for(let j = 0; j < modIDs.length; j++){
                parent = parent[modIDs[j]] || false;    // Reset parent module
            }
            modules.push(parent);   // Add the module to the module dependency list
        }else{  // If it is a module object
            modules.push(v); // Add to the module dependency list directly
        }
    })
    fn.apply(null, modules);    // Execute the callback function
}

// Method dependent on dom and k modules, in array form
F.module(["dom", "k"], function(){
    console.log(1);
})
// Method dependent on dom2 module and k.a method, in string form
F.module("dom2", "k.a", function(){
    console.log(2);
})

Daily Question

https://github.com/WindrunnerMax/EveryDay

Reference

https://www.jianshu.com/p/2359390737aa https://www.dazhuanlan.com/2020/03/09/5e65fa05c9bb7/ https://blog.csdn.net/WuLex/article/details/107350493