zoukankan      html  css  js  c++  java
  • 回调函数与DOM事件

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

    先看如下代码:

    1 document.addEventListener("DOMContentLoaded", function() {
    2   console.log("Init: 1");
    3   DOES_NOT_EXIST++; // error
    4 }, false);
    5 
    6 document.addEventListener("DOMContentLoaded", function() {
    7   console.log("Init: 2");
    8 }, false);

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

    结果是这样的:

    Init: 1
    
    Uncaught ReferenceError: DOES_NOT_EXIST is not defined
    
    Init: 2

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

    问题来了.

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

    1 $(document).ready(function() {
    2   console.log("Init: 1");
    3   DOES_NOT_EXIST++; // error
    4 });
    5 
    6 $(document).ready(function() {
    7   console.log("Init: 2");
    8 });

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

    Init: 1
    Uncaught ReferenceError: DOES_NOT_EXIST is not defined

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

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

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

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

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

    Init: 1
    
    Init: 2

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

    那该如何解决呢?

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

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

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

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

    这里是代码:

     1 var currentHandler;
     2 
     3 if (document.addEventListener) {
     4   document.addEventListener("fakeEvents", function() {
     5     // execute the callback
     6     currentHandler();
     7   }, false);
     8 
     9   var dispatchFakeEvent = function() {
    10     var fakeEvent = document.createEvent("UIEvents");
    11     fakeEvent.initEvent("fakeEvents", false, false);
    12     document.dispatchEvent(fakeEvent);
    13   };
    14 } else { // MSIE
    15 
    16   document.documentElement.fakeEvents = 0; // an expando property
    17 
    18   document.documentElement.attachEvent("onpropertychange", function(event) {
    19     if (event.propertyName == "fakeEvents") {
    20       // execute the callback
    21       currentHandler();
    22     }
    23   });
    24 
    25   dispatchFakeEvent = function(handler) {
    26     // fire the propertychange event
    27     document.documentElement.fakeEvents++;
    28   };
    29 }
    30 
    31 var onLoadHandlers = [];
    32 function addOnLoad(handler) {
    33   onLoadHandlers.push(handler);
    34 };
    35 
    36 window.onload = function() {
    37   for (var i = 0; i < onLoadHandlers.length; i++) {
    38     currentHandler = onLoadHandlers[i];
    39     dispatchFakeEvent();
    40   }
    41 };

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

    Init: 1
    
    Uncaught ReferenceError: DOES_NOT_EXIST is not defined
    
    Init: 2
  • 相关阅读:
    奇怪的肚疼
    惊喜:vs2005 和 msdn 中文版 已经提供Subscriber 下载,MSDN全球订户可以下中文版爽了
    英语构语法(前、后缀部分)
    TSQL中的递归 作者:Alexander Kozak
    筹划向 Visual Studio 2005 导航控件的迁移 作者:Dave Donaldson Steven DeWalt
    Atlas客服端文件介绍
    Chinese lunar calendar for www.live.com
    帮助解决网页和JS文件中的中文编码问题的小工具
    ADO.NET 2.0 功能一览 作者:Bob Beauchemin
    Prototype.js 1.4中文使用手册PDF版下载
  • 原文地址:https://www.cnblogs.com/fangzhaolee/p/3719384.html
Copyright © 2011-2022 走看看