两个事件触发时运行代码

时间:2011-03-14 23:44:55

标签: javascript events language-agnostic

这主要是与语言无关的问题。

如果我正在等待两个事件完成(例如,两个IO事件或http请求),那么处理此问题的最佳模式是什么。我能想到的一件事是以下(伪js例子)。

request1.onComplete = function() {
  req1Completed = true;
  eventsCompleted();
}

request2.onComplete = function() {
  req2Completed = true;
  eventsCompleted();
}

eventsCompleted = function() {

  if (!req1Completed || !req2Completed) return;
  // do stuff

}

这是最有效的模式,还是有更优雅的方法来解决这个问题?

4 个答案:

答案 0 :(得分:4)

在进入细节之前,这里有一些利用lambda功能的整洁的东西:

function makeCountdownCallback(count, callback) {
    return function() {
        if (--count == 0)
            callback();
    };
}

request1.onComplete = request2.onComplete = makeCountdownCallback(2, function() {
    // do stuff
});

这显然假设每个事件最多触发一次,并且没有利用顺序。

答案 1 :(得分:2)

jQuery 1.5有Deferreds:http://api.jquery.com/category/deferred-object/

只有在触发某些事件时,您才能轻松将其设置为回叫。

答案 2 :(得分:1)

尝试#1 :这是一个不需要额外全局变量的解决方案:

request1.onComplete = function() {
    // register new handler for event2 here, overwriting the old one
    request2.onComplete = function() {
        // now they're both done
    }
}

request2.onComplete = function() {
    // register new handler for event1 here, overwriting the old one
    request1.onComplete = function() {
        // now they're both done
    }  
}

首先触发任何事件的处理程序将清除另一个旧处理程序并分配一个新处理程序,其中包含在两个事件完成后您需要执行的操作。因为我们在第一个事件的处理程序中重新分配第二个处理程序(无论哪个),我们总是知道在第二个处理程序完成时我们已经完成了。

尝试#2 :如果每个事件类型不同,这里会有效:

function onBoth(fn) {
    var last, done = false;
    return function(e) {
        if (last && last !== e.type && !done) {
            fn(); // done
            done = true;
        }
        last = e.type;
    }
}

例如,在用户同时滚动和点击之前,这不会提醒“完成”:

var both = onBoth(function() {
    alert("done")
});

document.addEventListener("scroll", both, false);
document.addEventListener("click", both, false);

尝试#3 :可以修改上一次尝试以适用于类似事件:

function onBoth(fn) {
    var last, done = false;
    return function(curr) {
        if (last && last !== curr && !done) {
            fn(); // done
            done = true;
        }
        last = curr;
    }
}

......应该像这样使用:

var check = onBoth(function() {
    alert("done")
});

request1.onComplete = function() {
    check(arguments.callee);
}

request2.onComplete = function() {
    check(arguments.callee);
}

基本上,这通过存储对最近执行的回调的引用来检查已经执行了两个不同的回调。它的用法有点笨拙,但它可以完成工作(即如果每个事件执行多次,它仍然可以工作)。

答案 3 :(得分:0)

一种方法:http://tobireif.com/posts/waiting_for_two_events/

Q.spread([
  getA(), getB()
], function(a, b) {
  // Use the results a and b.
// Catch errors:
}).catch(function(error) {
  // Minimal for this example:
  console.log(error);
});

lib位于https://github.com/kriskowal/q