YUI2.8自定义事件的一个小bug
YUI2.8的自定义事件如果添加了两个相同的侦听函数,在移除这些侦听函数时会有错误:
- var testEvent = new YAHOO.util.CustomEvent("testEvent");
- testEvent.subscribe(eventHandler);
- testEvent.subscribe(eventHandler);
- testEvent.unsubscribe(eventHandler);
- function eventHandler(){
- alert("testEvent fire");
- }
- testEvent.fire();
- //只会显示一个"testEvent fire"
复制代码上面看似没问题,注册了两个相同的侦听函数,执行一次unsubscribe移除了一个,于是只剩一个侦听函数,但事实不是这样:
- var testEvent = new YAHOO.util.CustomEvent("testEvent");
- testEvent.subscribe(eventHandler);
- testEvent.subscribe(eventHandler);
- testEvent.subscribe(eventHandler);
- testEvent.subscribe(eventHandler);
- testEvent.unsubscribe(eventHandler);
- function eventHandler(){
- alert("testEvent fire");
- }
- testEvent.fire();
- //只会显示两个"testEvent fire"
复制代码注册四个相同的侦听函数,执行了一次unsubscribe,却只剩下两个侦听函数有效。
原因
看unsubscribe的源码,在移除侦听函数时用了这样一个循环:
- for (var i=0, len=this.subscribers.length; i<len; ++i) {
- var s = this.subscribers[i];
- if (s && s.contains(fn, obj)) {
- this._delete(i);
- found = true;
- }
- }
- ....
- _delete: function(index) {
- var s = this.subscribers[index];
- if (s) {
- delete s.fn;
- delete s.obj;
- }
- this.subscribers.splice(index, 1);
- }
复制代码问题出在,执行this.subscribers.splice(index,1)时数组长度变了,被删除的元素位置会被下一个元素位置顶替,而for循环里的i继续叠加,就会跳过漏检查这个位置的新元素。
修正方法
1.如果想一次unsubscribe移除所有相同的侦听函数,只需把for改成倒序遍历:
for (var i=this.subscribers.length-1; i>-1; i–)
这样在删除过程中数组元素个数和位置变化也不会导致漏检查。
2.如果想让unsubscribe一次只移除一个侦听函数,应该在for里找到符合条件的元素时跳出循环:
- for (var i=0, len=this.subscribers.length; i<;len; ++i) {
- var s = this.subscribers[i];
- if (s && s.contains(fn, obj)) {
- this._delete(i);
- found = true;
- break;
- }
- }
复制代码不知实际应用中会不会有同时注册两个相同的侦听函数的情况,有的话也是非常少的,所以此bug没什么威胁~
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论