原文: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. PHP中对数据库操作的封装

    在动态网面设计中很多都要涉及到对数据库的操作,但是有时跟据需要而改用其它后台数据库,就需要大量修改程序.这是一件枯燥.费时而且容易出错的功作.其实我们可以用PHP中的类来实现对数据库操作的封装,从而使 ...

  2. Ubuntu14.04安装和配置Tomcat8.0.12

    Ubuntu14.04长的好看,所以一时间很感兴趣,研究各种软件的安装和开发环境的配置.今天先把安装的tomcat 8.0.12的教程分享给大家.如果你需要,请收藏!!!   官方网站下载最新的tom ...

  3. synergy在Windows和ubuntu 多台PC共享一套键盘鼠标

    UBUNTU 服务端安装: sudo apt-get install quicksynergy window 客户端安装: http://www.9ht.com/xz/68108.html#addre ...

  4. hdoj - 5202 Rikka with string (BestCoder Round #37 ($))

    http://acm.hdu.edu.cn/showproblem.php?pid=5202 字符串处理的题,要细心. 给定一个只包含小写字母和问号的字符串,让我们还原出本来的字符串,把问号替换成任意 ...

  5. ubuntu 搭建Erlang开发环境

    首先,打好库: sudo apt-get install build-essential sudo apt-get install libncurses5-dev sudo apt-get insta ...

  6. Qt之国际化

    简介 Qt国际化属于Qt高级中的一部分,本想着放到后面来说,上节刚好介绍了Qt Linguist,趁热打铁就一起了解下. 对于绝大多数的应用程序,在刚启动时,需要加载默认的语言(或最后一次设置的语言) ...

  7. get 与post 的接收传值方式

    1.get方法接收值写法 string ad = Request["name"]; 2.post方法接收值写法 <%string a = Request.Form[" ...

  8. python处理ajax请求

    先要起一个服务 server.py,可以支持python的cgi脚本. #!coding:utf8 from BaseHTTPServer import HTTPServer from CGIHTTP ...

  9. 08day2

    引爆炸弹 贪心 [问题描述] 有 n 个炸弹,有些炸弹牵了一根单向引线(也就是说引线只有在这一端能被炸弹点燃),只要引爆了这个炸弹,用引线连接的下一个炸弹也会爆炸.每个炸弹还有个得分,当这个炸弹被引爆 ...

  10. 【英语】Bingo口语笔记(22) - Talk系列

    talk back 顶嘴 talk somebody in to something 劝某人做某事 tal somebody out of something 劝某人不做某事