原文: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. dojo 十一 jsonp

    官方教程:Getting Jiggy with JSONPDojo对Ajax实现的框架XHR的功能很强大,但 XHR 框架的函数有一问题就是不能跨域访问,浏览器不允许 XHR 对象访问其他域的站点.此 ...

  2. Eclipse插件安装与使用 —— Properties Editor

    一.下载     首先当然是下载插件啦! 下载地址:http://sourceforge.jp/projects/propedit/downloads/40156/jp.gr.java_conf.us ...

  3. NDK(8)"Unknown Application ABI"的解决方案

    ndk 调试本地应用时 报错如下 : console信息: [2015-08-17 19:52:05 - NdkSample] Unknown Application ABI: [2015-08-17 ...

  4. python 捕获 shell 脚本的输出结果

    import subprocessoutput =Popen(["mycmd","myarg"], stdout=PIPE).communicate()[0] ...

  5. Android findBugs

    1.Bug:DM_BOXED_PRIMITIVE_FOR_PARSING "Boxing/unboxing to parse a primitive", A boxed primi ...

  6. 网络攻击之二:XSS(之一是SQL注入,前面有文章)

    学习了 http://www.oschina.net/question/565065_57506 (这里做了转载 http://blog.csdn.net/stilling2006/article/d ...

  7. poj 2479 (DP)

    求一个区间内连续两段不相交区间最大和. // File Name: 2479.cpp // Author: Missa_Chen // Created Time: 2013年06月22日 星期六 16 ...

  8. 【笨嘴拙舌WINDOWS】GDI绘制区域

    在默认情况下,Gdi绘画操作的使用白纸(窗口的客户区)黑字(Pen的颜色)!前面我们已经讲过如何改笔,现在来学习改变白纸(GDI的绘制区域) 正常的纸为一个矩形形状!有时候小孩不小心撕掉纸的一角,不小 ...

  9. Mybatis foreach

    批量删除: <delete id= "deleteBatchByXXX" parameterType= "list"> delete from 表名 ...

  10. UVa 11093 Just Finish it up

    从第一个加油站开始枚举起点,如果到第i个加油站油量不够的话,那么1~i个加油站都不可能是起点. 将第i+1个加油站作为起点继续枚举. 比如说,第一个加油站开始最多跑到第5个加油站,那么第二个加油站不可 ...