Два синхронизированных события, создающие бесконечный цикл

У меня есть текстовая область, которую я синхронизирую с GoInstant. вот как выглядит код:

var myRoom = platform.room('myRoom');
var myKey = myRoom('myKey');

// Listen to set events on the platform key and update a textarea
myKey.on('set', function(textAreaContent) {
  $('textarea').val(textAreaContent);
});

// When the textarea changes, set the platform key
$('textarea').on('change', function(){
  var textAreaContent = $(this).val();
  myKey.set(textAreaContent, function(err) {
    if (err) throw err;
  });
})

Это создает бесконечный цикл при обновлении одного текстового поля, т. Е. При изменении значения текстовой области, это вызывает обновление ключа платформы, что, в свою очередь, изменяет значение текстовой области бесконечно...

РЕДАКТИРОВАТЬ: На основе верхнего ответа я придумал следующий конструктор:

function BounceProtection() {
  var remoteUpdate = false; // remote toggle
  this.local = function(cb) {
    if (remoteUpdate) return;
    cb();
  };
  this.remote = function(cb) {
    remoteUpdate = true;
    cb();
    remoteUpdate = false;
  };
}

Таким образом, я могу создавать объекты bounceProtection по мере необходимости для защиты нескольких ключей даже при асинхронной природе js.

var myKeyBP = new BounceProtection();

3 ответа

Решение

Быстрый метод предотвращения бесконечного цикла распространения:

// Infinite loop prevention
var bounceProtection = {
  remoteUpdate: false, // remote toggle
  local: function(cb) {
    if (this.remoteUpdate) return;
    cb();
  },
  remote: function(cb) {
    this.remoteUpdate = true;
    cb();
    this.remoteUpdate = false;
  }
};

var myRoom = platform.room('myRoom');
var myKey = myRoom.key('myKey');

myKey.on('set', function(textAreaContent) {
  bounceProtection.local(function() {
    $('textarea').val(textAreaContent);
  });
});

$('textarea').on('change', function(){
  var textAreaContent = $(this).val();
  bounceProtection.remote(function() {
    myKey.set(textAreaContent, function(err) {
      if (err) throw err;
    });
  });
});

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

Я также предлагаю вам присвоить атрибуту textarea атрибут ID, так как кажется, что вы работаете с одной текстовой областью, но выполняете поиск по тегам, который неэффективен и легко нарушается при добавлении другой текстовой области на страницу.

var myRoom = platform.room('myRoom');
var myKey = myRoom('myKey');

var $textarea = $('textarea');

function setKey() {
  var textAreaContent = $(this).val();
  myKey.set(textAreaContent, function(err) {
    if (err) throw err;
  });
}

// Listen to set events on the platform key and update a textarea
myKey.on('set', function(textAreaContent) {
  $textarea.off('change', setKey); // Remove listener
  $textarea.val(textAreaContent);
  $textarea.on('change', setKey); // Reapply listener
});

// When the textarea changes, set the platform key
$textarea.on('change', setKey);

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

myKey.on('set', function(textAreaContent) {
  var $textarea = $('textarea');
  if ($textarea.val() !== textAreaContent) { // compare values first
    $textarea.val(textAreaContent);
  }
});

// When the textarea changes, set the platform key
$('textarea').on('change', function(){
  var textAreaContent = $(this).val();
  myKey.set(textAreaContent, function(err) {
    if (err) throw err;
  });
})
Другие вопросы по тегам