запуск кода, когда два события сработали - PullRequest
7 голосов
/ 15 марта 2011

Это в основном вопрос, не зависящий от языка.

Если я жду завершения двух событий (скажем, двух событий ввода-вывода или http-запросов), каков наилучший шаблон для решения этой проблемы? Одна вещь, о которой я могу думать, это следующее (пример псевдо-JS).

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

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

eventsCompleted = function() {

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

}

Это самый эффективный шаблон или есть более элегантные способы решения этой проблемы?

Ответы [ 4 ]

4 голосов
/ 15 марта 2011

Прежде чем вдаваться в подробности, вот кое-что изящное, что использует преимущества лямбда-функций на моей голове:

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

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

Это, очевидно, предполагает, что каждое событие срабатывает максимум один раз, ивоспользоваться заказом.

2 голосов
/ 15 марта 2011

jQuery 1.5 имеет Deferreds: http://api.jquery.com/category/deferred-object/

Вы можете легко настроить их на обратный вызов, только когда были запущены некоторые события.

1 голос
/ 15 марта 2011

Попробуйте # 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
    }  
}

Обработчик, который запускает событие первым, очистит старый обработчик другого и назначитновый, который включает в себя то, что вам нужно сделать после завершения обоих событий.Поскольку мы переопределяем второй обработчик внутри обработчика первого события (в зависимости от того, что это), мы всегда знаем, что мы закончили, когда этот второй обработчик завершится.

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

Try # 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);
}

По сути, это проверяет выполнение двух разных обратных вызовов, сохраняя ссылку на последний выполненный обратный вызов.Его использование немного неуклюже, но оно выполняет свою работу (то есть все равно будет работать, если каждое из событий будет выполнено более одного раза).

0 голосов
/ 19 апреля 2015

Один из способов сделать это: 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);
});

Библиотека находится в https://github.com/kriskowal/q.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...