不要温柔地走入AMD

1.无依赖情况

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>一步步走入AMD</title>
    <script>
    
    var req = {};
    /*无依赖*/
    req.config = {
        "a":{
            deps:[],
            fn:function(){
                console.log("a");
            }
        },
        "b":{
            deps:[],
            fn:function(){
                console.log("b");
            }
        },
        "c":{
            deps:[],
            fn:function(){
                console.log("c");
            }
        },
    }
    var require = function(deps,fn){
        var config = req.config,
        deps_arr = [];

        // 1.找依赖,生成依赖数组
        for(var i=0,l = deps.length; i<l; i++){
            var deps_item = deps[i];
            deps_arr.push(config[deps_item].fn);
        }

        // 2.依赖数组,是入口函数的参数
        fn.apply(window,deps_arr);
    };

    require(["a","b"],function(a,b){
        a();
        b();
    });
    </script>
</head>
<body>
    
</body>
</html>

2.有依赖

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>不要温柔地走入AMD</title>
    <script>    
    var req = {};
    /*有依赖*/
    req.config = {
        "a":{
            deps:["b"],
            fn:function(b){
                return function(){
                    console.log("a");
                    b();
                }
                    
            }
        },
        "b":{
            deps:["c"],
            fn:function(c){
                return function(){
                    console.log("b");
                    c();
                }
                    
            }
        },
        "c":{
            deps:[],
            fn:function(){
                var private_c = "cc"
                return function(){
                    console.log("c");
                    console.log(private_c);
                }
                
            }
        }
    }
    var require = function(deps,fn){
        var config = req.config,
        deps_arr = [];

        var excute_obj = {},
        deps_chain = [];

        for(var i in config){
            deps_chain.push(i);
        }
            
        // 包装各个依赖函数
        deps_chain.forEach(function(configName){
            var item = config[configName],
            item_deps = item["deps"],
            item_fn = function(){
                return item["fn"].apply(window,excute_obj[configName]["deps"])();
            };
            excute_obj[configName] = {};
            excute_obj[configName]["fn"] = item_fn;

        });

        // 依赖函数的执行参数生成
        deps_chain.forEach(function(configName){
            var item = config[configName],
            item_deps = item["deps"],
            param_arr = [];


            item_deps.forEach(function(i){
                param_arr.push(excute_obj[i]["fn"]);
            });

            excute_obj[configName]["deps"] = param_arr;

            
        });

        console.log(excute_obj);

        

        deps.forEach(function(configName){
            deps_arr.push(excute_obj[configName]["fn"]);
        });

        fn.apply(window,deps_arr);
    };

    // bug:依赖设置错误
    require(["a"],function(a){
        a();
        
    });
    </script>
</head>
<body>
    
</body>
</html>

3.循环依赖判断

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>不要温柔地走入AMD</title>
    <script>    
    var req = {};
    /*有循环依赖*/
    req.config = {
        "a":{
            deps:["b","c"],
            fn:function(b,c){
                return function(){
                    console.log("a");
                    b();
                    c();
                }
                    
            }
        },
        "b":{
            deps:["c"],
            fn:function(c){
                return function(){
                    console.log("b");
                    c();
                }
                    
            }
        },
        "c":{
            deps:["a"],
            fn:function(){
                return function(){
                    console.log("c");
                }
                
            }
        }
    }
    var require = function(deps,fn){
        var config = req.config,
        deps_arr = [];

        var excute_obj = {},
        deps_chain = [];

        for(var i in config){
            deps_chain.push(i);
        }
        console.log(deps_chain);

        function arrayClone(arr){
            var _array = [];
            for(var i=0,l=arr.length; i<l; i++){
                _array.push(arr[i]);
            }
            
            return _array;
        }
        function loopDepJudge(currentKey,currentDeps, circleArr){
            var check_arr = [];
            check_arr.unshift(arrayClone(currentDeps) );

            var keyChain = [currentKey];
            // 开始循环
            (function(){
                var currentDeps = check_arr[0];
                // console.log(currentDeps);
                if(currentDeps.length > 0){
                    var nextKey = currentDeps.shift(),
                    nextDeps = circleArr[nextKey];
                    if(keyChain.indexOf(nextKey) > -1){        
                        keyChain = [false,nextKey,keyChain.pop()];
                        return;
                    }
                    else{
                        keyChain.push(nextKey);
                    }

                    if(nextDeps.length > 0){
                        check_arr.unshift(arrayClone(nextDeps));
                    }
                    else{
                        check_arr.shift();
                        keyChain = [currentKey];
                        if(check_arr.length == 0){
                            return;
                        }
                    }
                }
                else{
                    return;
                }
                arguments.callee();
            })();
            return keyChain;
        }

        (function(){
            // 循环依赖检测
            var circle_deps = {};
            deps_chain.forEach(function(configName){
                circle_deps[configName] = config[configName]["deps"];
            });

            deps_chain.forEach(function(configName){
                var key = configName,
                deps = arrayClone(circle_deps[key]);

                var keyChain = loopDepJudge(key,deps,circle_deps);
                if(keyChain[0] == false){
                    throw new Error("有循环依赖。他们是"+keyChain[1]+"" +keyChain[2]);
                }
                else{
                    console.log(keyChain)
                }
            });
            // var keyChain = loopDepJudge()
            
            // 包装各个依赖函数
            deps_chain.forEach(function(configName){
                var item = config[configName],
                item_deps = item["deps"],
                item_fn = function(){
                    return item["fn"].apply(window,excute_obj[configName]["deps"])();
                };

                excute_obj[configName] = {};
                excute_obj[configName]["fn"] = item_fn;

            });

            // 依赖函数的执行参数生成
            deps_chain.forEach(function(configName){
                var item = config[configName],
                item_deps = item["deps"],
                param_arr = [];


                item_deps.forEach(function(i){
                    param_arr.push(excute_obj[i]["fn"]);
                });

                excute_obj[configName]["deps"] = param_arr;

                
            });

            console.log(excute_obj);

        })();

        deps.forEach(function(configName){
            deps_arr.push(excute_obj[configName]["fn"]);
        });

        fn.apply(window,deps_arr);
    };

    require(["a"],function(a){
        a();
        
    });
    </script>
</head>
<body>
    
</body>
</html>

4.define函数定义

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>不要温柔地走入AMD</title>
    <script>    
    var req = {};
    /*define函数定义*/
    req.requireConfig = {};
    
    var define = function(deps,fn){
        var protocal = location.protocal,
        host = location.host,
        port = location.port,
        pathName = location.pathname,
        href = location.href,

        paths = req.userConfig.paths,
        baseUrl = req.userConfig.baseUrl || "";

        function baseUrlParse(baseUrl){
            var str_length = baseUrl.length,
            newBaseUrl = "";
            if(baseUrl.lastIndexOf("/") == str_length -1){

            }
            else{
                newBaseUrl = baseUrl + "/";
            }
            return newBaseUrl;
        }

        // 不支持IE
        // 1.获取当前js文件地址
        var scriptSrc = document.currentScript.src;

        for (var i in paths) {
            var path = paths[i],
            complete_path = "";

            // 2. 生成complete_path

            var backslash_pos = href.lastIndexOf("/"),
            slash_href = href.substring(0,backslash_pos+1),
            complete_path = slash_href + baseUrlParse(baseUrl) + path;


            // 3. 根据文件地址进行匹配,从而生成req.requireConfig
            if(scriptSrc == complete_path){
                req.requireConfig[i] = {
                    "deps":deps,
                    "fn":fn
                };
            }
        };
    };
    var require = function(deps,fn){
        function arrayClone(arr){
            var _array = [];
            for(var i=0,l=arr.length; i<l; i++){
                _array.push(arr[i]);
            }
            
            return _array;
        }
        function loopDepJudge(currentKey,currentDeps, circleArr){
            var check_arr = [];
            check_arr.unshift(arrayClone(currentDeps) );

            var keyChain = [currentKey];
            // 开始循环
            (function(){
                var currentDeps = check_arr[0];
                // console.log(currentDeps);
                if(currentDeps.length > 0){
                    var nextKey = currentDeps.shift(),
                    nextDeps = circleArr[nextKey];
                    if(keyChain.indexOf(nextKey) > -1){        
                        keyChain = [false,nextKey,keyChain.pop()];
                        return;
                    }
                    else{
                        keyChain.push(nextKey);
                    }

                    if(nextDeps.length > 0){
                        check_arr.unshift(arrayClone(nextDeps));
                    }
                    else{
                        check_arr.shift();
                        keyChain = [currentKey];
                        if(check_arr.length == 0){
                            return;
                        }
                    }
                }
                else{
                    return;
                }
                arguments.callee();
            })();
            return keyChain;
        }

        var config = req.requireConfig,
        deps_arr = [],
        excute_obj = {},
        deps_chain = [];

        for(var i in config){
            deps_chain.push(i);
        }
        
        // 循环依赖检测
        (function(){
            var circle_deps = {};
            deps_chain.forEach(function(configName){
                circle_deps[configName] = config[configName]["deps"];
            });

            deps_chain.forEach(function(configName){
                var key = configName,
                deps = arrayClone(circle_deps[key]);

                var keyChain = loopDepJudge(key,deps,circle_deps);
                if(keyChain[0] == false){
                    throw new Error("有循环依赖。他们是"+keyChain[1]+"" +keyChain[2]);
                }
                else{
                    console.log(keyChain)
                }
            });
        })();// 包装各个依赖函数
        deps_chain.forEach(function(configName){
            var item = config[configName],
            item_deps = item["deps"],
            item_fn = function(){
                return item["fn"].apply(window,excute_obj[configName]["deps"])();
            };
            excute_obj[configName] = {};
            excute_obj[configName]["fn"] = item_fn;

        });

        // 依赖函数的参数数组生成
        deps_chain.forEach(function(configName){
            var item = config[configName],
            item_deps = item["deps"],
            param_arr = [];


            item_deps.forEach(function(i){
                param_arr.push(excute_obj[i]["fn"]);
            });

            excute_obj[configName]["deps"] = param_arr;

            
        });

        // 主函数的参数数组生成
        deps.forEach(function(configName){
            deps_arr.push(excute_obj[configName]["fn"]);
        });

        fn.apply(window,deps_arr);
    };

    req.userConfig = {
        "baseUrl":"",
        "paths":{
            "a":"a.js",
            "b":"b.js",
            "c":"c.js"
        }
    };
    </script>
    <script type="text/javascript" src="b.js"></script>
    <script type="text/javascript" src="a.js"></script>
    <script type="text/javascript" src="c.js"></script>
    <script>
    require(["a"],function(a){
        a();
    });
    </script>
</head>
<body>
    
</body>
</html>

5.js加载器生成

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>不要温柔地走入AMD</title>
    <script>
    /*
    1.暂不支持shim
    */    
    var req = {};
    
    req.requireConfig = {};
    req.userConfig= {};
    // 用来记录js加载的数目
    req.jsLoadCount = 0;

    function baseUrlParse(baseUrl){
        var str_length = baseUrl.length,
        newBaseUrl = "";
        if(baseUrl.lastIndexOf("/") == str_length -1){

        }
        else{
            newBaseUrl = baseUrl + "/";
        }
        return newBaseUrl;
    }

    function getObjSize(obj){
        var size = 0;
        for(var i in obj){
            var item = obj[i];
            if(item !== null && typeof(item) !== "undefined"){
                size++;
            }
        }

        return size;
    }
    
    var define = function(deps,fn){
        var protocal = location.protocal,
        host = location.host,
        port = location.port,
        pathName = location.pathname,
        href = location.href,

        paths = req.userConfig.paths,
        baseUrl = req.userConfig.baseUrl || "";

        

        // 不支持IE
        // 1.获取当前js文件地址
        var scriptSrc = document.currentScript.src;

        for (var i in paths) {
            var path = paths[i],
            complete_path = "";

            // 2. 生成complete_path
            var backslash_pos = href.lastIndexOf("/"),
            slash_href = href.substring(0,backslash_pos+1),
            complete_path = slash_href + baseUrlParse(baseUrl) + path;


            // 3. 根据文件地址进行匹配,从而生成req.requireConfig
            if(scriptSrc == complete_path){
                req.requireConfig[i] = {
                    "deps":deps,
                    "fn":fn
                };
            }
        };
    };
    var require = function(deps,fn){
        // 检测js加载完毕与否
        var timer_loader = setTimeout(function(){
            if(req.jsLoadCount == 0){
                clearTimeout(timer_loader);
                mainRequire();
            }
            else{
                timer_loader();
            }
        },200);

function mainRequire(){
        function arrayClone(arr){
            var _array = [];
            for(var i=0,l=arr.length; i<l; i++){
                _array.push(arr[i]);
            }
            
            return _array;
        }
        function loopDepJudge(currentKey,currentDeps, circleArr){
            var check_arr = [];
            check_arr.unshift(arrayClone(currentDeps) );

            var keyChain = [currentKey];
            // 开始循环
            (function(){
                var currentDeps = check_arr[0];
                // console.log(currentDeps);
                if(currentDeps.length > 0){
                    var nextKey = currentDeps.shift(),
                    nextDeps = circleArr[nextKey];
                    if(keyChain.indexOf(nextKey) > -1){
                        keyChain = [false,nextKey,keyChain];
                        return;
                    }
                    else{
                        keyChain.push(nextKey);
                    }

                    if(nextDeps.length > 0){
                        check_arr.unshift(arrayClone(nextDeps));
                    }
                    else{
                        check_arr.shift();
                        keyChain = [currentKey];
                        if(check_arr.length == 0){
                            return;
                        }
                    }
                }
                else{
                    return;
                }
                arguments.callee();
            })();
            return keyChain;
        }
        var config = req.requireConfig,
        deps_arr = [],
        excute_obj = {},
        deps_chain = [];

        for(var i in config){
            deps_chain.push(i);
        }
        console.log(config);
        
        // 循环依赖检测
        (function(){
            var circle_deps = {};
            deps_chain.forEach(function(configName){
                circle_deps[configName] = config[configName]["deps"];
            });
            console.log(circle_deps);

            deps_chain.forEach(function(configName){
                var key = configName,
                deps = arrayClone(circle_deps[key]);

                var keyChain = loopDepJudge(key,deps,circle_deps);
                if(keyChain[0] == false){
                    throw new Error("前方高能,有循环依赖。他们是"+keyChain[1]+"" +keyChain[2]);
                }
                else{
                    console.log(keyChain)
                }
            });
        })();
        
        // 包装各个依赖函数
        deps_chain.forEach(function(configName){
            var item = config[configName],
            item_deps = item["deps"],
            item_fn = function(){
                return item["fn"].apply(window,excute_obj[configName]["deps"])();
            };
            excute_obj[configName] = {};
            excute_obj[configName]["fn"] = item_fn;

        });

        // 依赖函数的参数数组生成
        deps_chain.forEach(function(configName){
            var item = config[configName],
            item_deps = item["deps"],
            param_arr = [];


            item_deps.forEach(function(i){
                param_arr.push(excute_obj[i]["fn"]);
            });

            excute_obj[configName]["deps"] = param_arr;

            
        });

        // 主函数的参数数组生成
        deps.forEach(function(configName){
            deps_arr.push(excute_obj[configName]["fn"]);
        });

        fn.apply(window,deps_arr);
}
    };
    require.config = function(config_obj){
        req.userConfig = config_obj;
        req.jsLoadCount = getObjSize(config_obj.paths);

        function generateScript(url,loadCount){
            var _script = document.createElement('script');
            _script.type = 'text/javascript';
            _script.charset = 'utf-8';
            _script.async = true;
            _script.src = url;
            _script.onload = function(){
                req.jsLoadCount--;
            };
            _script.onerror = function(e){
                throw new Error(e);
            };

            var fs = document.getElementsByTagName('script')[0];
              fs.parentNode.insertBefore(_script, fs);
        }
        var href = location.href,
        baseUrl = req.userConfig.baseUrl || "";
        paths =  req.userConfig.paths;
        for(var i in paths){
            var path = paths[i],
            backslash_pos = href.lastIndexOf("/"),
            slash_href = href.substring(0,backslash_pos+1),
            complete_path = slash_href + baseUrlParse(baseUrl) + path;
            generateScript(complete_path);
        }
            

    }

    require.config({
        "baseUrl":"",
        "paths":{
            "c":"c.js?v=3",
            "a":"a.js",
            "b":"b.js"
        }
    });

    require(["a","b"],function(a,b){
        a();
        b();
    });
        
    </script>
    
</head>
<body>
    
</body>
</html>
原文地址:https://www.cnblogs.com/samwu/p/4542403.html