j engine -构建高性能、可监控的前端应用框架
DESCRIPTION
TRANSCRIPT
jEngine--构建高性能、可监控的前端应用框架
王 涛2012-03-02
应用框架—解决应用的实际问题
• 应用复杂,开发者多,需要引入模块化编程
• 需求紧,无遐优化,框架需要真正的 fast by default
• 单点故障多,可用性不高,应用的容错性要增强
• 浏览器多样,调试不便,引入统一的分层 log机制
前端代码无日志 , 线上故障发现晚 , 急需异常监控系统
整体框架图
沙箱 (core.sandbox.js)
应用核心(core.application.js)
FDEV4
首屏加载模块
延迟加载模块
延迟初始化模块
模块化编程—模块模块:
• 模块对整体架构的了解非常有限,它只知道 sandbox 的存在。
• 每个模块各司其职,共同构建了应用的正常运行。
模块化编程—模块代码示例!(function($){
var Sandbox,
configs = {
end:0
};
function lazyloadModule1(sb) {
Sandbox = sb;
return lazyloadModule1;
}
$.extend(lazyloadModule1,{
init:function(cfg){
this.config = $.extend(true, {}, configs, cfg);
Sandbox.on( Searchweb.Config.Events.DELETE, this.create);
},
create:function(data){
alert("lazyloadModule1 got the message:" + data.msg);
},
end:0
});
Searchweb.Business.lazyloadModule1 = lazyloadModule1;
})(jQuery);
模块化编程—模块
模块必须呆在相应的 sandbox 中,也许会很不舒服,但这对应用是安全的!
模块化编程—模块设计原则
• 不要在模块中创建全局变量。• 禁止访问该模块之外的 Dom 节点。
• 只允许调用自身的或是 sandbox 提供的方法。
• 不可直接引用其它模块的对象或调用其方法。
Sandbox 是通往外界的桥梁!
模块化编程—沙箱• 沙箱负责模块间的数据传递及事件交互
沙箱模块 1 模块 2
notify on
notifyon
模块化编程—沙箱Module1:
var data={msg:"send from Module1"};
Sandbox.notify (Searchweb.Config.Events.DELETE, data);
Module2:Sandbox.on ( Searchweb.Config.Events.DELETE, this.callback);
模块化编程—应用核心
模块生命周期管理 异常处理
消除SPOF
监控
容错性
注册
初始化
运行停止
销毁
模块化编程—应用核心代码示例register: function(moduleId, creator, opt){
moduleData[moduleId] = {
creator: creator,
instance: null
};
},
start: function(moduleId){
moduleData[moduleId].instance = moduleData[moduleId].creator(new Sandbox(this));
moduleData[moduleId].instance.init();
},
stop: function(moduleId){
var data = moduleData[moduleId];
if (data.instance){
data.instance.destroy();
data.instance = null;
}
}
模块化编程—应用核心代码示例// 注册所有首屏加载模块AppCore.register("mod-search-module1", Searchweb.Business.Module1);
AppCore.register("mod-search-module2", Searchweb.Business.Module2);
AppCore.register("mod-search-module3", Searchweb.Business.Module3);
AppCore.register(“mod-search-module4”, Searchweb.Business.Module4, {callback:function(){/* */}});
// 初始化所有首屏加载模块AppCore.startAll();
<div id=“mod-search-module1" data-mod-config= '{"name":"title","url":"http://china.alibaba.com/offer/post/json/validate_result.htm"}‘>
…
</div>
性能提升— Fast By Default
• 在模块管理中加入“懒注册”机制,从框架的层面解决性能问题 -- Fast By Default !
模块注册
首屏加载模块注册
延迟加载模块注册
延迟初始化模块注册
性能提升— Fast By Default/**
*@method: lazyRegister 延迟(加载 | 初始化)模块注册函数* @param: moduleId: 注册模块的名称( string )* @param: creator: 模块的构造函数( string|function ),如果为 string ,则会被 parse 成为 function* @param: els: 触发延迟加载模块的元素,可以是 id 、 dom 、 domArray(jquery dom 数组对象 )* @param: event: 延迟加载的驱动事件,可以是曝光事件、 dom 事件、 manual 事件 {exposure|manual|normal events like: click, mouseover, focus, mouseenter}* @param: opt : (optional) 延迟加载成功后的回调函数 {Object}
*/lazyRegister: function(moduleId, creator, els, event, opt){
var succeed = false;if(opt.init === false){
succeed = jEngine.Core.LazyModule.register(els, event, opt);}else{ var self = this; succeed = jEngine.Core.LazyModule.register(els, event, opt,
function(){self._lazyStart(moduleId, creator)});}return succeed;
}
性能提升— Fast By DefaultlazyLoadModuleInit:function(){
// 曝光延迟加载模块的注册方式AppCore .lazyRegister(“mod-search-lazyload1”, “Searchweb.Business.lazyloadModule1”, $(".domDetail"), 'exposure',{ threshold:200,module:this.config.lazyurl.lazyModule1
});
// 交互事件驱动延迟加载模块的注册方式AppCore .lazyRegister("mod-search-lazyload2", "Searchweb.Business.lazyloadModule2", '#mod-search-lazyload2', 'mouseover',{module:this.config.lazyurl.lazyModule2 });
// 使用代码主动触发的延迟加载模块的注册方式 Sandbox.notify("jEngine.lazyLoad", moduleId);
AppCore.lazyRegister("mod-search-lazyload3",
"Searchweb.Business.lazyloadModule3", null, 'manual',{module:this.config.lazyurl.lazyModule3 });
},
性能提升— Fast By Default模块注册的三种方式统一定义在一个文件中:
性能提升— Fast By Default<html>
<body>… 省略 …
<!--页面上只应该有一个 js文件被放置在 <script>标签中加载,其余都是无阻塞加载 --> <script type=“text/javascript” src=“http://style.china.alibaba.com/js/app/search/v4.0/core/core.seed.js”></script>
<script>jEngine.Core.Loader.js(“http://style.china.alibaba.com/js/lib/fdev-v4/core/fdev-min.js”)
.js(“http://style.china.alibaba.com/js/app/search/v4.0/core/core.logger.js”)
.js(“http://style.china.alibaba.com/js/app/search/v4.0/core/core.sandbox.js”)
.js(“http://style.china.alibaba.com/js/app/search/v4.0/core/core.lazymodule.js”) .js(“http://style.china.alibaba.com/js/app/search/v4.0/core/core.application.js”) // 核心类加载完毕,开始加载业务类
.js(“http://style.china.alibaba.com/js/app/search/v4.0/example/config.js”) .js(“http://style.china.alibaba.com/js/app/search/v4.0/example/module1.js”)
.js(“http://style.china.alibaba.com/js/app/search/v4.0/example/lazyinitmodule.js”) .js(“http://style.china.alibaba.com/js/app/search/v4.0/example/app.start.js”); </script> </body>
</html>
性能提升— Fast By Default
完美的 js 加载瀑布图:
便于开发调试—分层 log机制
Firefox :
IE :
修改自叶周全分层 log 类,添加了 IE 下的 log 机制:
增强容错性—全局性异常处理区分线上线下模式的方法:var DEBUG_MOD = (typeof window.dmtrack ==="undefined") ? true : false;
try{
…
}
catch (ex) {
if(!DEBUG_MOD){ $.logger.error(“log error message:” + ex.message); // 线上模式记录异常}else{
throw ex; //debug 模式下抛异常给浏览器}
}
增强容错性—全局性异常处理 var instance = new module.creator(sb), name, method; instance.options = opt;
//debug 模式下 try catch 不起作用,交由浏览器自己处理错误。//online 模式下可以把错误信息记录在日志服务器上。if (!DEBUG_MOD){ for (name in instance){
method = instance[name]; if (typeof method == "function"){ instance[name] =
function(name, method){ return function (){ try { return method.apply(this, arguments); } catch(ex) { $.logger.error(moduleId +
" throw error: " + name + "()-> " + ex.message); } }; }(name, method); } } } return instance;
增强容错性—全局性异常处理• 模块中的每个函数都被自动加入到异常处理机制中。
• 线上异常的定位可以非常迅速。
异常监控—与 Dragoon的完美结合 //online 模式下针对 warning和 error才需要报警
if(!DEBUG_MOD){ if(level == 0 || level == 1){
(new Image()).src = $.Logger.errorUri + this.getBrowserInfo() + errorMsg; }}
异常监控—与 Dragoon的完美结合
异常监控—与 Dragoon的完美结合• 更加完善的前端异常监控系统
后期完善方向
• 性能优化结合后端的继续深入
• 模块化编程更完善的支持
On The Road