newland
newland copied to clipboard
全新的加载器(兼容CommonJS与Require的AMD与SeaJS)
现在所有模块都将匿名化,同步化。新版的加载器相同说是相当于原生require的加强版,同时require多个模块时,返回一个数组。
var array = require(["./aaa","./bbb","./ccc"]) //相当于 var array = []; array[array.length] = require("./aaa") array[array.length] = require("./bbb") array[array.length] = require("./ccc")
亦可以在后面加函数
var array = require(["./aaa","./bbb","./ccc"],function(a, b, c){ //....................... })
模块允许多种定义法
//纯node.js方法 var a = require("httpflow") console.log(a)
//CommonJS的匿名函数法 define({ aa:1, bb:2 })
//CommonJS的匿名函数法 define(function(){ exports.aaa = "aaa" })
//CommonJS的匿名函数法 define(function(){ exports.aaa = "aaa" return "xxxx" //注意这时exports对象将变xxxx返回值所取替,当返回为不为undefined时 })
//CommonJS的匿名函数法 define(["./aaa"],function(require, exports, module){ console.log(module)//指向当前模块 })
//ADM的匿名函数法 define(["./aaa","./bbb"],function(a,b){ console.log(module)//指向当前模块,module总是存在的 console.log(a) })
我们再看一下新旧模块系统实现的对比:
$.mix({ //模块加载的定义函数 define: function( name, deps, factory ){//模块名,依赖列表,模块本身 //这是一个空接口 }, //模块加载的请求函数 require: function( deps, factory, errback ){ var _deps = {}, args = [], dn = 0, cn = 0; factory = typeof factory == "function" ? factory : $.noop; String(deps +"").replace( $.rword, function( str ){ if(str.indexOf("./") === 0){ str = str.replace(/^\.\//, "" ); } dn++; var match = str.match( rmodule ); var id = "@"+ match[1];//模块的ID var filename = match[2];//模块的URL if(!filename){ id = id.replace(/\.js$/,"") filename = $.path.join( factory.parent || $.require.root, match[1] ); //path.join会自动处理../的情况 filename = /\.js$/.test(filename) ? filename : filename +".js"; } var input = id; try{//先把它当成原生模块进行加载 returns[ id ] = require( match[1] );//require自身是缓存请求的 mapper[ id ] = { state : 2 } process.nextTick( $._checkDeps );//每成功加载一个模块就进行依赖检测 }catch(e){ input = filename } if( !_deps[ input ] ){ args.push( input ); _deps[ input ] = "司徒正美"; } if( input === filename && !mapper[ input ] ){ //防止重复生成节点与请求 mapper[ input ] = {};//state: undefined, 未安装; 1 正在安装; 2 : 已安装 loadJS( filename ); }else if( mapper[ input ].state === 2 ){ cn++; } }); var id = factory.id || "@cb"+ ( cbi++ ).toString(32); if( typeof errback == "function" ){ errorStack.push( errback );//压入错误堆栈 } mapper[ id ] = mapper[ id ] || {} $.mix( mapper[ id ], {//创建或更新模块的状态 callback: factory, id: id, deps: _deps, args: args, state: 1 }, false); //在正常情况下模块只能通过_checkDeps执行 loadings.unshift( id ); process.nextTick( $._checkDeps ); }, // 模块加载的检测依赖函数,如果一个模块所依赖的其他模块的状态都是2了,那么将它也改成2,并执行回调 _checkDeps: function (){ loop: for ( var i = loadings.length, filename; filename = loadings[ --i ]; ) { var obj = mapper[ filename ], deps = obj.deps || {}; for( var key in deps ){ if( deps.hasOwnProperty( key ) && mapper[ key ].state != 2 ){ continue loop; } } //如果deps是空对象或者其依赖的模块的状态都是2 if( obj.state !== 2){ loadings.splice( i, 1 );//必须先移除再安装,防止在IE下DOM树建完后手动刷新页面,会多次执行它 obj.state = 2 ; var id = obj.id; var ret = collect_rets( id, obj.args ||[], obj.callback ); if( id.indexOf("@cb") === -1 ){ returns[ id ] = ret; $.log("已加载" + id + "模块","cyan", 6 ); $._checkDeps(); } } } } }); //把模块有关信息都存放在这里 var mapper = $.require.cache = {} //从returns对象取得依赖列表中的各模块的返回值 function collect_rets( name, args, fn ){ for(var i = 0, argv = []; i < args.length ; i++){ argv.push( returns[ args[i] ] ); } var ret = fn.apply( null, argv );//执行模块工厂,然后把返回值放到returns对象中 $.debug( name );//想办法取得函法中的exports对象 return ret; } //模块加载的加载函数 function loadJS( filename ){ try{ $.define = function(){//诡变的$.define var args = Array.apply([],arguments); if( typeof args[1] === "function" ){//处理只有两个参数的情况 [].splice.call( args, 1, 0, "" ); } args[2].id = filename; //模块名 args[2].parent = filename.slice(0, filename.lastIndexOf( $.path.sep ) + 1) //取得父模块的文件夹 mapper[ filename ].state = 1; process.nextTick( $._checkDeps );//每成功加载一个模块就进行依赖检测 $.require( args[1], args[2] ); } require( filename ); }catch( e ){ $.log( e, "red", 3); for(var fn; fn = errorStack.shift(); ){ fn();//打印错误堆栈 } } } //用于模块加载失败时的错误回调 var errorStack = [];
新加载系统则精简许多了
var rparams = /[^\(]*\(([^\)]*)\)[\d\D]*/ var toString = ({}).toString; global. define = function(deps, callback){ var caller = arguments.callee.caller var args = caller.arguments;//取得当前模块的参数列表,依次为exports, require, module, __filename,__dirname var common = { exports: args[0], require: args[1], module: args[2] } var array = [], ret; if(arguments.length === 1 && toString.call(deps) === "[object Object]"){ ret = deps;//如果是对象,那么它就是exports }else if(typeof deps == "string" ){ deps = deps.match( $.rword );//如果依赖列表是字符串,则转换为数组 } if(Array.isArray(deps)){//如果存在依赖关系,先加载依赖关系 for(var i = 0,el ; el = deps[i++] ;){ array[ array.length ] = args[1]( el );//require某个模块 } } callback = arguments[arguments.length - 1]; if(typeof callback == "function"){ var match = callback.toString().replace(rparams,"$1") || []; var a = common[match[0]]; var b = common[match[1]]; var c = common[match[2]]; if( a && b && c && a != b && b != c && a != c ){//exports, require, module的位置随便 ret = callback.apply(0, [a, b, c]); }else{ ret = callback.apply(0, array); } } if(typeof ret !== "undefined"){ args[2].exports = ret; } return args[2].exports; } var $ = {} $.require = function(deps, callback){ if(typeof deps == "string"){ return require(deps) } var array = []; for(var i = 0, el; el = deps[i++];){ array.push( require(el) ) } if(typeof callback == "function"){ callback.apply(0, array); } return array }
详细的测试用例请见app\public\scripts\test
请问一下正美大大,你这个东东是基于nodejs的一个Web框架对吗,里面包含你之前的模块加载等框架不。是不是你之前做的前端的好东东都融合在里面了?