2014-01-31 3 views
0

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

function update() { 
    buildUpdate(function(result) { 
     // send result to clients 
    }); 
} 

Это нормально работает правильно. Однако, если я что-то типа:

// data state 1 

update(); // this time, buildUpdate() won't take a long time 

// do some work resulting in: 
// data state 2 

update(); // this time, buildUpdate() will take a long time 
      // and thus will finish after the third call 

// do some work resulting in: 
// data state 3 

update(); // this time, buildUpdate() won't take a long time 

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

  • получает обновление, рассчитанное на основе состояния данных 1
  • Получает обновление рассчитывается на основе состояния данных 3
  • Получает обновление рассчитывается на основе состояния данных 2 (это обновление не следует отправлять)

Есть ли какой-либо шаблон дизайна или функция, которая помогает избежать такого случая?

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

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

+1

A: Независимо от вашей платформы быть node.js этот вопрос не имеет ничего общего с Node.js B : Что вы хотите, чтобы обновление было вызвано во второй раз?Учитывая ответ на вопрос B, я думаю, что я могу помочь вам с лучшей идеей, чем ваш случайный идентификатор. –

+0

@GeorgeJempty A: Вы правы, я прошу прощения за неправильную маркировку. B: См. Пересмотренный вопрос. – ted

ответ

3

Самый простой, вероятно, будет добавить функцию обратного вызова

function update(callback) { 
    buildUpdate(function(result) { 
     // send result to clients 

     if (typeof callback == 'function') callback(); 
    }); 
} 

и сделать

update(function() {   // when the first one finishes 
    update(function() {  // run the second one 
     update(function() { // and when the second is finished, the third 
       update();  // and so on.... 
     }); 
    }); 
}); 

Если добавить async промежуточное программное обеспечение вы бы иметь более продвинутые методы, доступные для решения поведения асинхронным.

+0

Благодарим вас за предложение. Есть ли способ, который может применяться к более чем двум вызовам обновления? (например, в пересмотренном примере) – ted

+0

@ted - применять его столько раз, сколько вы хотели бы (см. обновленный ответ), но если вы собираетесь это много раз, есть лучшие способы, поскольку экземпляры рекурсии ум, но это немного сложнее, чем просто вложение функций. – adeneo

+0

Вам следует рассмотреть возможность использования jQuery-объекта обещания http://api.jquery.com/promise/ для обработки ваших асинхронных проблем. –

0

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

var outdated = function(f, cb) { 
    var counter = 0; 
    var finished = -1; 
    return function() { 
     var no = counter++; 
     a = [].slice.call(arguments); 
     a.unshift(function() { 
      if(no > finished) { 
       finished = no; 
       cb.apply(this, arguments); 
      } 
     }); 
     f.apply(this, a); 
    }; 
}; 

Давайте рассмотрим следующий пример:

var example = outdated(function(cb, a) { 
    setTimeout(function() { 
     cb(a); 
    }, a * 1000); 
}, function(c) { 
    console.log('finished '+c); 
}); 

example(1); 
example(4); 
example(2); 

Это приведет к следующему выходу:

finished 1 
finished 2 

finished 4 не печатается, как она называлась до finished 2 но закончилась после того, как Это.

Для решения актуальной проблемы, как указано в вопросе, я бы вызвать функцию так:

var update = outdated(buildUpdate, function(result) { 
    // send update to clients 
}); 

update(); 
// do some changes 
update(); 
Смежные вопросы