不要温柔地走入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>
合乎自然而生生不息。。。