如何使用jQuery Deferred with custom events?

时间:2011-02-15 20:34:54

标签: javascript jquery jquery-1.5 jquery-deferred

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

jQuery 1.5中的新Deferred逻辑似乎是理想的管理方式,除了when()方法接受返回promise()的deferred对象(或普通的js对象,但是when()立即完成而不是等待,这对我来说毫无用处。)

理想情况下,我想做类似的事情:

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

将这两种技术结合起来的最佳方式是什么?

2 个答案:

答案 0 :(得分:40)

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 );

答案 1 :(得分:12)

你可以让“customevent1”和“customevent2”的事件处理程序在它们触发时发出“延迟”实例。您可以使用“$ .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对象来跟踪这两个条件,并在设置两个条件时触发“解析”:

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");

现在,这些事件的事件处理程序只需要在事件发生时调用“解决”事件:

    df.resolve(event.type);

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

我觉得你可以做的另一件事就是编写一个jQuery插件来初始化元素的Deferred对象,并将它存储在“.data()”属性中。然后,您可以编写一些可供事件处理程序用来发信号的插件,以及其他用于为多事件序列注册处理程序的插件。我觉得这很酷,但我需要花一些时间来思考它。