mass Framework在后端的核心模块
mass Framework前后通吃,后端是基于node.js组建起来。后端与前端不一样,是依赖于node.js内置模块提供的一些API,因此前端那些依赖于浏览器提供的DOM API的模块无法复用。现在掐指一算,基本上核心模块上只有lang, flow能用得上,more则多一点,如random, pinyin, base64, uuid...
node.js内置了模块加载机制,这与我在前端使用的API非常不一致,我就再把它包装一层。核心模块与前端的核心模块在其他方法也尽量保持一致,当然像domReady在后端就不需要,去掉。如类型判定,由于是V8引擎,支持ECMA262v5,因此可以写得精简。最大的不同是,DEBUG用到mass.log,它的第二个参数是表示格式化高亮。
代码是暂时丢在这里,以后还要做各种扩展的!
( function (){ //后端部分 2011.12.4 by 司徒正美 function mass(){} var version = 0.1, class2type = { "[object global]" : "Global" , "null" : "Null" , "NaN" : "NaN" , "undefined" : "Undefined" }, toString = class2type.toString; /** * 糅杂,为一个对象添加更多成员 * @param {Object} target 目标对象 * @param {Object} source 属性包 * @return {Object} 目标对象 */ function mix(target, source){ var args = [].slice.call(arguments), key, ride = typeof args[args.length - 1] == "boolean" ? args.pop() : true ; target = target || {}; for ( var i = 1; source = args[i++];){ for (key in source) { if (ride || !(key in target)) { target[key] = source[key]; } } } return target; } var rformat = /<code\s+style=[ '"](.*?)[' "]\s*>([\d\D]+?)<\/code>/ig; var formats = { bold : [1, 22], italic : [3, 23], underline : [4, 24], inverse : [7, 27], strike : [9, 29] }; var colors = {}; [ 'black' , 'red' , 'green' , 'yellow' , 'blue' , 'magenta' , 'cyan' , 'white' ].forEach( function (word,i){ colors[word] = i }); colors.gray = 99; function format (arr, str) { return '\x1b[' + arr[0] + 'm' + str + '\x1b[' + arr[1] + 'm' ; }; mix(mass,{ //为此版本的命名空间对象添加成员 rword : /[^, ]+/g, v : version, "@debug" : true , root: process.cwd(), /** * 数组化 * @param {ArrayLike} nodes 要处理的类数组对象 * @param {Number} start 可选。要抽取的片断的起始下标。如果是负数,从后面取起 * @param {Number} end 可选。规定从何处结束选取 * @return {Array} */ slice: function (nodes, start, end) { for ( var i = 0,n = nodes.length, result = []; i < n; i++){ result[i] = nodes[i]; } if (arguments.length > 1) { return result.slice(start , (end || result.length)); } else { return result; } }, /** * 用于取得数据的类型或判定数据的类型 * @param {Any} obj 要检测的东西 * @param {String} str 要比较的类型 * @return {String|Boolean} */ type : function (obj, str){ var result = class2type[ (obj == null || obj !== obj )? obj : toString.call(obj) ] || "#" ; if ( result.charAt(0) === "#" ){ if (Buffer.isBuffer(obj)){ result = 'Buffer' ; //返回构造器名字 } else { result = toString.call(obj).slice(8,-1); } } if (str){ return str === result; } return result; }, /** * 用于调试 * @param {String} s 要打印的内容 * @param {Boolean} color 进行各种颜色的高亮,使用<code style="format:blod;color:red;background:green"> * format的值可以为formats中五个之一或它们的组合(以空格隔开),背景色与字体色只能为colors之一 */ log: function (s, color){ if (color){ s = s.replace(rformat, function (a,style,ret){ style.toLowerCase().split( ";" ).forEach( function (arr){ arr = arr.split( ":" ); var type = arr[0].trim(),val = arr[1].trim(); switch (type){ case "format" : val.replace(/\w+/g, function (word){ if (formats[word]){ ret = format(formats[word],ret) } }); break ; case "background" : case "color" : var array = type == "color" ? [30,39] : [40,49] if ( colors[val]){ array[0] += colors[val] ret = format(array,ret) } } }); return ret; }); } console.log(s); }, /** * 生成键值统一的对象,用于高速化判定 * @param {Array|String} array 如果是字符串,请用","或空格分开 * @param {Number} val 可选,默认为1 * @return {Object} */ oneObject : function (array, val){ if ( typeof array == "string" ){ array = array.match(mass.rword) || []; } var result = {},value = val !== void 0 ? val :1; for ( var i=0,n=array.length;i < n;i++){ result[array[i]] = value; } return result; }, mix:mix }); mass.noop = mass.error = function (){}; "Boolean,Number,String,Function,Array,Date,RegExp,Arguments" .replace(mass.rword, function (name){ class2type[ "[object " + name + "]" ] = name; }); var rmodule = /([^(\s]+)\(?([^)]*)\)?/, names = [], //需要处理的模块名列表 rets = {}, //用于收集模块的返回值 cbi = 1e4 ; //用于生成回调函数的名字 var map = mass[ "@modules" ] = {}; //执行并移除所有依赖都具备的模块或回调 function resolveCallbacks(){ loop: for ( var i = names.length,repeat, name; name = names[--i]; ) { var obj = map[name], deps = obj.deps; for ( var key in deps){ if (deps.hasOwnProperty(key) && map[key].state != 2 ){ continue loop; } } //如果deps是空对象或者其依赖的模块的状态都是2 if ( obj.state != 2){ names.splice(i,1); //必须先移除再执行 var fn = obj.callback; rets[fn._name] = fn.apply( null ,incarnate(obj.args)); //只收集模块的返回值 obj.state = 2; repeat = true ; } } repeat && resolveCallbacks(); } function incarnate(args){ //传入一组模块名,返回对应模块的返回值 for ( var i = 0,ret = [], name; name = args[i++];){ ret.push(rets[name]); } return ret; } function deferred(){ //一个简单的异步列队 var list = [],self = function (fn){ fn && fn.call && list.push(fn); return self; } self.method = "pop" ; self.fire = function (fn){ while (fn = list[self.method]()){ fn(); } return list.length ? self : self.complete(); } self.complete = mass.noop; return self; } var nativeModules = mass.oneObject( "assert,child_process,cluster,crypto,dgram,dns," + "events,fs,http,https,net,os,path,querystring,readline,repl,tls,tty,url,util,vm,zlib" ) function useNativeRequire(name,url){ var nick = name.slice(1); if (nativeModules[nick]){ map[name].state = 2; rets[name] = require(nick); resolveCallbacks(); } else { url = url || mass.root+ "/" + nick + ".js" ; try { require(url); resolveCallbacks() } catch (e){ mass.stack(Function( 'mass.log("\033[31m' +e+ '\033[39m")' )); mass.stack.fire(); //打印错误堆栈 } } } mass.mix(mass,{ stack : deferred(), define: function (name,deps,callback){ //模块名,依赖列表,模块本身 if ( typeof deps == "function" ){ //处理只有两个参数的情况 callback = deps; deps = "" ; } callback._name = "@" +name; //模块名 this .require(deps,callback); }, require: function (deps,callback,errback){ //依赖列表,正向回调,负向回调 var _deps = {}, args = [], dn = 0, cn = 0; (deps + "" ).replace(mass.rword, function (url,name,match){ dn++; match = url.match(rmodule); name = "@" + match[1]; //取得模块名 if (!map[name]){ //防止重复生成节点与请求 map[name] = { }; //state: undefined, 未加载; 1 已加载; 2 : 已执行 useNativeRequire(name,match[2]); //加载模块 } else if (map[name].state === 2){ cn++; } if (!_deps[name] ){ args.push(name); _deps[name] = "司徒正美" ; //去重 } }); var cbname = callback._name; if (dn === cn ){ //在依赖都已执行过或没有依赖的情况下 if (cbname && !(cbname in rets)){ map[cbname].state = 2 //如果是使用合并方式,模块会跑进此分支(只会执行一次) return rets[cbname] = callback.apply( null ,incarnate(args)); } else if (!cbname){ //普通的回调可执行无数次 return callback.apply( null ,incarnate(args)) } } cbname = cbname || "@cb" + (cbi++).toString(32); if (errback){ mass.stack(errback); //压入错误堆栈 } map[cbname] = { //创建或更新模块的状态 callback:callback, deps:_deps, args: args, state: 1 }; //在正常情况下模块只能通过resolveCallbacks执行 names.unshift(cbname); resolveCallbacks(); } }); exports.mass = global.mass = mass; })(); </code\s+style=[ '"](.*?)[' "]\s*> |
如果您觉得此文有帮助,可以打赏点钱给我支付宝1669866773@qq.com ,或扫描二维码


机器瞎学/数据掩埋/模式混淆/人工智障/深度遗忘/神经掉线/计算机幻觉/专注单身二十五年
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
2010-12-05 选择器切割正则的进化
2010-12-05 mass.query v3 发布