【问题标题】:How to use jQuery Deferred with custom events?如何将 jQuery Deferred 与自定义事件一起使用?
【发布时间】:2011-02-15 20:34:53
【问题描述】:

我有两个抽象进程(例如,在 js 对象中使用不暴露其内部的显示模块模式进行管理)在它们完成时触发 custom events。我想在两个自定义事件都触发时执行一个操作。

jQuery 1.5 中新的Deferred 逻辑似乎是一种理想的管理方式,除了 when() 方法采用返回 promise() 的延迟对象(或普通的 js 对象,但随后 when( ) 立即完成而不是等待,这对我来说没用)。

理想情况下,我想做这样的事情:

//execute when both customevent1 and customevent2 have been fired
$.when('customevent1 customevent2').done(function(){
  //do something
});

结合这两种技术的最佳方法是什么?

【问题讨论】:

    标签: javascript jquery jquery-1.5 jquery-deferred


    【解决方案1】:

    http://jsfiddle.net/ch47n/

    我创建了一个小插件,它创建了一个新的 jQuery.fn.when 方法。

    语法是:

    jQuery( "whatever" ).when( "event1 event2..." ).done( callback );
    

    它在内部广泛使用 jQuery.when() 并确保在解析之前已在集合中的所有元素上触发了所有事件。


    实际插件代码如下:

    ( function( $ ) {
    
        $.fn.when = function( events ) {
    
            var deferred, $element, elemIndex, eventIndex;
    
            // Get the list of events
            events = events.split( /\s+/g );
    
            // We will store one deferred per event and per element
            var deferreds = [];
    
            // For each element
            for( elemIndex = 0; elemIndex < this.length; elemIndex++ ) {
                $element = $( this[ elemIndex ] );
                // For each event
                for ( eventIndex = 0; eventIndex < events.length; eventIndex++ ) {
                    // Store a Deferred...
                    deferreds.push(( deferred = $.Deferred() ));
                    // ... that is resolved when the event is fired on this element
                    $element.one( events[ eventIndex ], deferred.resolve );
                }
            }
    
            // Return a promise resolved once all events fired on all elements
            return $.when.apply( null, deferreds );
        };
    
    } )( jQuery );
    

    【讨论】:

    • 优秀的解决方案。如果有很多节点或事件,使用“每个”的多个内部循环可能会带来一些性能问题,但老实说,我目前看不到改进此解决方案的方法。感谢您的回答。
    • jsfiddle.net/FfPXq/6 使用 for 循环并使用 $.Deferred(fn) 签名来创建适当的闭包以解除绑定。
    • +1 太棒了!我将使用这样的东西来异步加载自定义 UI 控件。在 deferreds 开始发挥作用之前,管理多个级别的事件一直很讨厌!
    【解决方案2】:

    您可以让“customevent1”和“customevent2”的事件处理程序在它们触发时分别发出一个“Deferred”实例信号。您可以使用 "$.when()" 然后将这两者合二为一,这就是您仅在触发两个自定义事件后才触发处理程序的地方。

    var df1 = $.Deferred(), df2 = $.Deferred();
    $('whatever').bind('customevent1', function() {
      // code code code
      df1.resolve();
    }).bind('customevent2', function() {
      // code code code
      df2.resolve();
    });
    
    var whenBoth = $.when(df1, df2);
    
    whenBoth.then(function() {
      // code to run after both "customevent1"
      // and "customevent2" have fired
    });
    

    旧答案,为了完整起见,这里

    您可以创建自己的 Deferred 对象来跟踪这两个条件并在两者都设置时触发“resolve”:

    function watchEvents() {
      var df = $.Deferred();
    
      var flags = {};
      $.each(Array.prototype.slice.call(arguments, 0), function() {
        flags[this] = false;
      });
    
      var realResolve = df.resolve.bind(df);
      df.resolve = function(eventName) {
        flags[eventName] = true;
        for (var ev in flags) if (flags[ev] === false) return;
        realResolve();
      };
    
      return df;
    }
    

    现在你可以调用那个函数了:

    var df = watchEvents("customevent1", "customevent2");
    

    现在,这些事件的事件处理程序只需要在捕获事件时对该事物调用“resolve”即可:

        df.resolve(event.type);
    

    每个处理程序都报告自己的类型。只有当您调用“watchEvents”时请求的所有事件类型都发生时,您在“df”上注册的处理函数才会真正被调用。

    在我看来,您可以做的另一件事是编写一个 jQuery 插件,该插件为元素初始化一个 Deferred 对象,并将其存储在“.data()”属性中。然后,您可以编写更多插件,事件处理程序可以使用这些插件来发出信号,并编写其他插件来为多事件序列注册处理程序。我想那会很酷,但我需要花点时间思考一下。

    【讨论】:

    • 上面的“df.reserve”是错字吗?我在 jQuery Deferred API 文档中找不到保留属性。如果您可以提供指向它的链接(如果存在),我将不胜感激。
    • 另外 - 有更好的方法可以做到这一点,但我正在考虑几种替代方法 - 我会尽快更新。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-09
    • 2021-05-25
    相关资源
    最近更新 更多