-
Notifications
You must be signed in to change notification settings - Fork 41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
关于trigger时异常处理的建议 #1
Comments
加 try catch 不是很合适,因为 JavaScript 的单线程特性,导致 events 实现时是顺序调用 handlers 的,这些 handlers 之间可能有顺序依赖,当前面的出错时,再继续调用后面的,后面的状态已经可能不对,就如种田一样,如果插秧这一步出了问题,再往后执行状态已经不可控,非预期了。 针对页游这个例子,感觉应该是每一个有可能出错的 handler 自身应该考虑到自己出错,出错时,内部有 try catch 处理。具体实现可以通过父类来统一处理,所有有可能出错的 handler,继承自同一个父类,父类里集中处理好就行。 |
因为项目调整过很多次,这个文件已经过时。请参考 http://aralejs.org/events/tests/runner.html |
感谢反馈,但大家的作息不太健康啊~ :) @lifesinger @lepture 理解尊重玉伯的观点,但仍建议未来考虑异常捕获,三点原因: document.addEventListener("keydown",function(e){
throw new Error();
console.log("第一个", e.keyCode);
});
document.addEventListener("keydown",function(e){
console.log("第二个", e.keyCode); //这里会不受其它handler中异常的影响
}); 3 在 issue#2 中,玉伯提到event更像广播,各个handler没有顺序,互不影响,这点我非常同意。try catch就是对这点更好的保证。 |
补充楼上第1条: |
错误捕捉这个我考虑下,是个经典问题了,可以看下明城翻译的这篇文档: http://www.gracecode.com/posts/2940.html 我仔细考虑下。 |
很棒的文章,分析的很全面。 感谢对这个问题的关注。 |
感觉用这种方式就够了,捕获到错误后打印出来(不支持 console 的不输出),并中断当次循环,继续下一个循环。 |
这个还是别加啊 我很同意 backbone 作者的这句话:
Backbone 社区有过讨论,最后是决定不处理: https://groups.google.com/forum/#!msg/backbonejs/bvUVuovKfms/F8kJZqFeiU0J |
我不太认同 @lifesinger 的观点。 觉得不同 handler 之间不应该出现依赖(原生事件机制也是无序的),因此不同 handler 应该也是在独立作用域中,抛出的异常不应该其他 handler。 明城的博客分析的很棒,如果是站在结果的角度,最喜欢基于事件的机制,独立的作用域可以保证结果和原生及期望的一致,而且异常抛出的异常可以被统一监控捕获。缺点是复杂了点,逻辑和性能等都是需要考量的(try/catch 在捕获到异常时也有性能问题)。 但是 finally 的方案也可以接受,简单实用。前端监控中提供了 p.s. 如果不 rethrow ex,finally 貌似没什么必要。但是 rethrow 的异常不能被浏览器捕获(亦不触发 window.onerror),意义不大。 |
之前跟 @lifesinger 讨论过,希望 events 尽可能的保持简单,而且用户的使用场景无法预知,比如有些场景就需要第一个报错而停止之后的执行。 使用者也可以对 callback 再做一层封装。
|
不认同。
确实需要依赖的,考虑:
var flag = false;
obj.on("a", function(){
try{}catch(ex){
flag = true;
throw ex; // monitor.error(ex);
}
});
obj.on("a", function(){
if(flag){return;}
// XXX
}); 觉得这个保持简单有点一厢情愿,而用户的正当需求却没有被满足。 |
@hotoo 我们的观点在基本层面是一致的: events 应该是天女散花,无顺序,无依赖。任何 handler 都不应该有顺序依赖性。我一直非常强调这一点。 但是无顺序依赖,并不代表无其他依赖,比如
比如上面这种情况,因为空间的共享性,实质上会让 handler 之间是有依赖的。 同样的,对于前端开发来说,由于共享了同一个 DOM 树,实际上 handler 之间也是有可能互相影响,很难从理论上做保证完全不依赖。 这样,用 try catch 去保证无依赖性,实质性却并不能保证,反而可能引起一连串不正确的操作。 就如 Backbone 作者所说的那样:
不加 try catch,跟保持简单性没半毛钱关系,而是为了更正确的处理问题。 某个 handler 或一批 handler 是否应该在抛错时不影响其他 handler 的执行,这是 user-land 的范畴,可以自己封装。倘若 events 层封装的话,反而剥夺了用户的选择权,使得用户不再能选择抛错不执行的策略。不封装的话,用户想怎么着都行,更拥有自由。 |
两种方式的分歧点并不是“能不能发现错误”,而是一旦出错会不会影响其他 callback。现在的这种做法是将权利交给使用者,使用者可以按照自己的情况去进一步封装。 |
其实吧,这个功能,做成啥样使用者就怎么用,不会有人去蛋疼的加一个 |
最重要的是两个不同 handler,A 更新数据库或 DOM 失败或什么原因造成的异常,跟 B 是没有关系的,除非它明确对 A 的这个更新有依赖。不依赖 A 的 B 应该可以继续完成它的工作。 浏览器原生的类似案例:
另外,我上面提到的第 2种『使用标记』法,也是一种交给用户的方法。只不过是反过来了,默认认为各 handler 无依赖,如果你们有依赖,需要你们自己配合解决。 上面举的例子没能说服我,还可以举其他例子吗? |
仔细想了下,还是得分两个场景来说:展现型页面和功能型页面。 对于展现型页面来说,比如淘宝首页,页面某一个区块出问题时,最好不影响另一个区块的展现,因为一般来说,各个区块之间不会有强关联。感觉这也是浏览器设计之初,独立 script 之间互不影响的初衷。 对于功能型页面来说,比如 Gmail,当页面某一个区域出问题时,经常意味着底层数据或网络出了问题,这时最好的处理方式是,都停下来,统一给出错误或重试提示,而不是继续进行操作,因为操作已经不可预期,很可能造成不必要甚至错误的操作,比如发了一封错误的邮件等。 Backbone 使用场景应该是功能型页面,因此非常坚持出了任何错误,都不再继续执行后续 handler 的策略。类似的 YUI3 也是如此。 对于支付宝来说,由于支付操作涉及用户金额,有可能存在以下可能性:
当 handler A 出错时,校验数据有可能停留在过去值,也有可能被设置成错误值 这就是说,对于功能型页面来说,一旦有代码错误(不一定是 handler 引发的),就应该尽可能做到停止代码执行,并告知用户出了问题,可以刷新页面重试。 这就如一锅汤,一旦滴进了一滴毒药,只要发现有一个人中毒了,最明智的做法就是立刻不再继续把汤盛给其他人,否则毒死一批人,罪孽就大了。 问题的核心是,要判断滴进汤里的是毒药,还是仅仅是一粒沙子。对展现型页面来说,经常是沙子,无伤大雅,但对功能型页面来说,我情愿假设都是毒药,应立刻告知所有人并停止喝汤。 |
Arale 定位为面向支付宝的前端解决类库,以后会有更多金融型产品出现,都是偏功能型的,因此我觉得还是假设都是毒药的好。 对于展现型的页面,若基于 Arale 开发,如果想确保不被一粒老鼠屎坏掉一锅汤,可以自己再次封装下。 events 本身还是尽量少做一些功能,少其实是为了多。倘若多做了一层处理,反而能支持的场景变少了。 |
所以,我还是坚持默认为监听者间不依赖。需要依赖的监听者自行协同。支持的场景并没有减少,反而是更多了(可以和已知的依赖者协同)。 |
就是不依赖呀,这条是一致的,没有分歧的 |
其实这个问题很简单处理嘛: events.suppress = true
events.on('a', fn) 非 suppress 下,用户自己 try catch events.suppress = false
events.on('a', function() {
try {
} catch (e) {}
}) |
@lepture 你这是两面派,徒增了一点点不必要的复杂性 |
认真读了<事件触发的一个细节设计上下>, @lifesinger 举的两个应用情境,功能型和展现型,来对应停止策略与继续策略。 如果站在灵活性普适性的角度,是值得继续挖掘的。“少即是多”理念OK,但如果解决办法是“仅可以使用者对自己的业务做try catch”,我认为这是arale.js/events能力上的不健全,可以考虑再做一些改动。我的一些观点如下:
p.s. 分享一下我们应用情景,拓展大家思路:我做的一个游戏开发过程是这样了, 先做基本的功能流程开发,event-based, 例如”游戏胜利“这个环节,逻辑开发好后,产品说需要挂特效,用event 就很方面,event.on("win",function(){/全屏动画特效/}); event.on("win",function(){/声音特效/}); 如果终止问题来了,用户如果声音解码有问题,出现异常,那么就看不到胜利画面了, 甚至不能胜利。 |
@huipengyu 针对你最后提到的应用场景,我的想法是: event.on("win", errorProne(function() { /* 声音特效 */ }))
event.on("win", errorProne(function() { /* 全屏动画特效 */ })) 通过 errorProne 方法,来将有可能出错的 handler 再封装一层。 |
这个 issue 就讨论到这吧,events 是广播式触发的,每个 handler 之间是无依赖的,这个大家都是认同的。 events 还是保留“少即是多”的理念,给开发者更大的空间。如果需要处理异常可根据 @lifesinger 上面说的再进行一层封装。 |
Hi,aralers :)
最近考虑使用arale的events,但发现在trigger的时候,对for循环中的apply没有异常捕获。这样的话,如果注册上来的某个callback出现异常,那么callback list中后续的所有回调函数都将得不到执行。
个人认为这样不够合理,所以有后续建议,仅为抛砖。apply放入try catch中,出现异常立即处理,考虑以下处理办法
注:原来在写页游时遇到的一个情景:我们游戏的战斗逻辑等各种复杂逻辑是通过events来处理的,这样效果很好,当所有逻辑与渲染开发完毕后,通过event的形式挂载了音效模块,即对各种战斗事件挂载播放不同音乐。但如果音乐播放出现异常,基于event的其他游戏逻辑不会受到影响。
注:本来想写个test验证一下,但是tests中的runner跑不起来,http://aralejs.org/tools/seajs-helper.js 与 http://aralejs.org/tools/jasmine-runner.js 都是404。spm用的不是很熟,是不是我用错了。
The text was updated successfully, but these errors were encountered: