原文:http://dean.edwards.name/weblog/2009/03/callbacks-vs-events/

先看如下代码:

 document.addEventListener("DOMContentLoaded", function() {
console.log("Init: 1");
DOES_NOT_EXIST++; // error
}, false); document.addEventListener("DOMContentLoaded", function() {
console.log("Init: 2");
}, false);

你预期当页面加载后,console下会出现什么结果?

结果是这样的:

Init: 1

Uncaught ReferenceError: DOES_NOT_EXIST is not defined

Init: 2

重点在于: 两个事件监听函数都执行了.虽然在第一个事件监听函数中出现了错误,但并没有阻止第二个函数的执行.

问题来了.

接下来我们基于回调函数系统的代码.使用jQuery:

 $(document).ready(function() {
console.log("Init: 1");
DOES_NOT_EXIST++; // error
}); $(document).ready(function() {
console.log("Init: 2");
});

此时你从console下看到了什么?没错,是这样:

Init: 1
Uncaught ReferenceError: DOES_NOT_EXIST is not defined

好吧,这意味着回调函数系统是极其脆弱的.一旦任何一个回调函数中抛出了异常,则余下的回调函数序列将不再执行.

在实际开发环境中,这意味着一个写得烂的插件可以令其他插件无法初始化.

Dojo与jQuery有相同的问题,而YUI包装了try/catch机制,它会让回调函数中的错误悄悄地被捕获:

 YAHOO.util.Event.onDOMReady(function() {
console.log("Init: 1");
DOES_NOT_EXIST++; // this will throw an error
}); YAHOO.util.Event.onDOMReady(function() {
console.log("Init: 2");
});

所以你将在console看到如下结果:

Init: 1

Init: 2

几近完美的初始化! 貌似没什么好担心的了,除了那些你看不到的错误.

那该如何解决呢?

下面的解决方案是这样的: 使用回调函数混合真正的事件调度.

我们可以触发一个自定义事件,并在该事件的监听函数中,迂回地执行回调函数.

因为每个事件处理程序都有它自己的上下文,所以,即便在事件处理函数内发生了错误,也不会影响到我们的回调函数系统了.

回调函数序列中的每一个函数都将被执行.

这里是代码:

 var currentHandler;

 if (document.addEventListener) {
document.addEventListener("fakeEvents", function() {
// execute the callback
currentHandler();
}, false); var dispatchFakeEvent = function() {
var fakeEvent = document.createEvent("UIEvents");
fakeEvent.initEvent("fakeEvents", false, false);
document.dispatchEvent(fakeEvent);
};
} else { // MSIE document.documentElement.fakeEvents = 0; // an expando property document.documentElement.attachEvent("onpropertychange", function(event) {
if (event.propertyName == "fakeEvents") {
// execute the callback
currentHandler();
}
}); dispatchFakeEvent = function(handler) {
// fire the propertychange event
document.documentElement.fakeEvents++;
};
} var onLoadHandlers = [];
function addOnLoad(handler) {
onLoadHandlers.push(handler);
}; window.onload = function() {
for (var i = 0; i < onLoadHandlers.length; i++) {
currentHandler = onLoadHandlers[i];
dispatchFakeEvent();
}
};

这次,执行结果当然又是我们预期的了:

Init: 1

Uncaught ReferenceError: DOES_NOT_EXIST is not defined

Init: 2

回调函数与DOM事件的更多相关文章

  1. C#将C++动态库的回调函数封装成事件

    关于C#调用C++动态库的文章很多,调用动态库中回调函数的方法也不在少数.但大多数调用回调函数的方法依然保留了C++的语法特点. 比如有一段C++的回调函数代码,为了表达它的意思,我把注释也粘贴了进来 ...

  2. DOM事件机制

    前言 本文主要介绍DOM事件级别.DOM事件模型.事件流.事件代理和Event对象常见的应用,希望对你们有些帮助和启发! 本文首发地址为GitHub博客,写文章不易,请多多支持与关注! 一.DOM事件 ...

  3. VC++ 回调函数及使用方法(转)

    转载:http://blog.csdn.net/vsooda/article/details/7435801 转载:http://blog.csdn.net/lincyang/article/deta ...

  4. SetTimer 与 回调函数

    在控制台应用程序中,SetTimer的函数原型为: UINT_PTR SetTimer( HWND hWnd, // handle to window UINT_PTR nIDEvent, // ti ...

  5. 关于js中的回调函数callback

    来源于:http://www.jianshu.com/p/6bc353e5f7a3 前言 其实我一直很困惑关于js 中的callback,困惑的原因是,学习中这块看的资料少,但是平时又经常见,偶尔复制 ...

  6. 关于 js 中的回调函数 callback

    本文写于1年前 曾经的学习文章如今拿出来分享 前言 其实我一直很困惑关于js中的callback,困惑的原因是,学习中这块看的资料少,但是平时又经常见,偶尔复制一下前人代码,功能实现了也就不再去追其原 ...

  7. python异步回调函数的实现

    #coding:utf-8 from socket import * import time #简单的服务器程序 监听用户连接,接收用户发来的信息,并返回反馈 def main(): HOST = & ...

  8. 关于js中的回调函数callback,通俗易懂

    前言 其实我一直很困惑关于js 中的callback,困惑的原因是,学习中这块看的资料少,但是平时又经常见,偶尔复制一下前人代码,功能实现了也就不再去追其原由,这么着,这个callback的概念就越来 ...

  9. 原生js判断css3动画过度(transition)结束 transitionend事件 以及关键帧keyframes动画结束(animation)回调函数 animationEnd 以及 css 过渡 transition无效

      上图的 demo 主要讲的 是 css transition的过渡回调函数transitionend事件: css3 的时代,css3--动画 一切皆有可能: 传统的js 可以通过回调函数判断动画 ...

随机推荐

  1. MyBaits的各种基本查询方式

    <?xml version="1.0" encoding="gbk"?> <!DOCTYPE mapper PUBLIC "-//m ...

  2. 你猜……你再猜

    『男』:你喜欢我吗? 『女』:你猜. 『男』:喜欢. 『女』:你再猜. 『男』:--

  3. How Uuencoding Works

    做题目学习  https://www.zhihu.com/question/26598476/answer/45396765 http://email.about.com/od/emailbehind ...

  4. Oracle INV - SO line backorder API

    --Sales Order Lines to backorder API--===================================--SET serveroutput on size ...

  5. hibernate基础(1)

    hibernate基础1.hibernate介绍与动手入门体验  问题:模型不匹配(java对象模型与数据库关系模型不匹配)  解决: 1.使用JDBC手工转换        2.使用ORM(Obje ...

  6. 无锁编程(五) - RCU(Read-Copy-Update)

    RCU(Read-Copy Update) RCU就是指读-拷贝修改,它是基于其原理命名的.对于被RCU保护的共享数据结构,读操作不需要获得任何锁就可以访问,但写操作在访问它时首先拷贝一个副本,然后对 ...

  7. HTML5中的localStorage用法

    存储数据的方法就是直接给window.localStorage添加一个属性,例如:window.localStorage.name 或者 window.localStorage["name& ...

  8. tc srm 632 500 (规律)

    We have a sequence of N positive integers: a[0] through a[N-1]. You do not know these integers. All ...

  9. [ionic开源项目教程] - 第5讲 如何在项目中使用全局配置

    第5讲 如何在项目中使用全局配置? Q:ionic开发,说纯粹一点,用的就是html+css+js,那么无疑跟web开发的方式是类似的.在这里给大家分享一个小技巧,如何在项目中使用全局配置? A:我的 ...

  10. mysql约束(自己原先总结的有点不准)

    约束* 约束是添加在列上的,用来约束列的! 1. 主键约束(唯一标识) ****非空*** ****唯一*** ****被引用****(学习外键时) * 当表的某一列被指定为主键后,该列就不能为空,不 ...