标签:
页面中有多个功能模块,怎么在一个模块出了问题之后,保证其它模块的正常工作。
上面的差不多就是面试官的原话了,姑且称之为模块间错误隔离问题
第一反应是动态按需加载代码,用户操作发生后再加载对应模块代码,面试官(后文简称:对面)说所有模块代码都是在页面载入时加载的,不允许动态加载。
第二反应是error事件处理器return true,对面问确定这样做能隔离错误吗?不确定,好吧。。接着想
第三反应是try-catch,对面问怎么个try-catch法?说用try把各个模块包裹起来啊,也可以用工厂。。哦,那你写个工厂给我看看。。然后就傻傻地写了个这:
function getModule(type){ switch(type){ case Consts.type1 : return function(){ try{ Modules[type](); }catch(err){ // fix } }; break; ... } }
看对面不是很满意,就又补充说也可以把case里的匿名方法提出来,作为一个包装工具,但就只能做统一错误处理,而用这个可以针对模块做不同的错误处理,各有各的好处。。。对面勉强点头
之后对面沉默了很久,2分钟吧,有些忐忑,就弱弱地问是不是上个问题的答案不是您想要的?对面说:还行,用异常处理包起来确实可以。。
但感觉和对面想要的答案还是有些差距,所以有了本文
从上面的面试过程能找出几个子问题:
先给出测试结果:
function getSafeFun(fun){ // 集中处理错误 return function(){ try{ fun(); }catch(err){ if (err instanceof TypeError) { // 类型不匹配 } else if (err instanceof ReferenceError) { // 引用错误 } else{ // ... } } }; } function getSafeFun2(fun, errHandler){ // 针对函数处理错误 return function(){ try{ fun(); }catch(err){ errHandler(); } }; }
上面的是基础包装工具,还可以进一步封装,添一个好用的外观(Facade):
// 配置数据 var Modules = {}; Modules.mod1 = { desc : "模块1", method : errorFun }; Modules.mod2 = { desc : "模块2", method : fun }; /* * 统一模块调用接口 */ function use(moduleName, errHandler){ if (typeof errHandler === "function") { getSafeFun2(Modules[moduleName].method, errHandler)(); } else { getSafeFun(Modules[moduleName].method)(); } }
直接用use传入模块名和可选的错误处理器就可以隔离错误了,感觉好多了
不需要工厂,工厂是根据给定的参数返回对应类型的东西,而我们所做的不过是用try包裹了一下而已,和工厂没多大关系,感觉和装饰、外观的关系更大一点。。当然,重要的是好用,而不是一定要用什么模式
测试代码:
<script type="text/javascript"> script1 alert(1); </script> <script type="text/javascript"> alert(2); </script>
运行结果:2,script标签能够隔离错误,所以动态加载也能隔离错误
测试代码:(在head里的script标签中插入如下代码)
window.onerror = function(e){ return true; // 不报错 }
运行结果:不报错,也不会alert 1,对程序员而言没什么作用,不能隔离错误
测试代码:
// 闭包1 (function(){ closure alert(1); })(); // 闭包2,无法执行,因为闭包1出错了 (function(){ alert(2); })();
运行结果:没有alert任何东西,只要闭包1和2在同一个script标签或者同一个外部js文件中,闭包2都会因为闭包1出错而无法执行,所以闭包不能隔离错误
当然不能强制要求所有编码人员都在调用模块的时候用try包裹,我们至少得有一个包装工具,像这样的:
function getSafeFun(fun){ // 集中处理错误 return function(){ try{ fun(); }catch(err){ if (err instanceof TypeError) { // 类型不匹配 } else if (err instanceof ReferenceError) { // 引用错误 } else{ // ... } } }; } function getSafeFun2(fun, errHandler){ // 针对函数处理错误 return function(){ try{ fun(); }catch(err){ errHandler(); } }; } /* 测试 */ function errorFun(){ errorFunction alert(1); } function fun(){ alert(2); } getSafeFun(errorFun)(); getSafeFun(fun)();
现在有了getSafeFun()和getSafeFun2(),可以少写一点try了,但还是得要求所有编码人员自己看情况调用才能隔离错误,还是不科学,应该再添点什么
// 配置数据 var Modules = {}; Modules.mod1 = { desc : "模块1", method : errorFun }; Modules.mod2 = { desc : "模块2", method : fun }; /* * 统一模块调用接口 */ function use(moduleName, errHandler){ if (typeof errHandler === "function") { getSafeFun2(Modules[moduleName].method, errHandler)(); } else { getSafeFun(Modules[moduleName].method)(); } } /* 测试 */ use("mod1"); use("mod1", function(){ alert("fix"); }); use("mod2");
现在就比较人性化了,只留一个入口,只需要告诉编码人员以前的模块调用方式过时了,现在的新API是use即可
三.结论
抛开问题本身,上面的所有测试结果可以归纳如下:
标签:
原文地址:http://www.cnblogs.com/ayqy/p/4466553.html