Как убить функцию Javascript, если она снова вызвана?

У меня есть окно поиска на моей веб-странице с флажками, чтобы пользователь мог фильтровать свои результаты. Только один флажок можно проверить сразу.

Когда установлен флажок, мой код отключается и применяет фильтр к списку и возвращает правильные результаты.

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

Есть ли какой-либо способ в Javascript сообщить функции, что она была вызвана снова, и она должна остановить все, кроме этого последнего запроса?

Ответы

Ответ 1

Вы хотите обернуть свой обратный вызов onclick в функцию debouncing, например

http://underscorejs.org/#debounce

Скажите, что у вас это

function search() {
    // ...
}

$jquery(".myFilterCheckboxes").click(search);

Вы должны просто изменить приведенное выше:

// Only allow one click event / search every 500ms:
$jquery(".myFilterCheckboxes").click(_.debounce(search, 500));

Там есть много функций debouncing, и писать собственное не очень важно, если вы не можете или не хотите включать underscore.js.

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

Как отмечали другие, может быть больше смысла просто отключать флажки/событие click во время вашего поиска. В этом случае попробуйте что-то вроде этого:

function disableClick(elem) {
  elem.unbind("click");
  elem.attr("disabled", true);
}

function enableClick(elem, onclick) {
  // Enable click events again
  elem.live("click", search);
  // Enable the checkboxes
  elem.removeAttr("disabled");
}

function search() {
  var boxes = $jquery(".myFilterCheckboxes");
  disableClick(boxes);
  $.get(...).always(function() {
    enableClick(boxes, search);
  });
}

$jquery(".myFilterCheckboxes").live("click", search);

Зачем отключать событие click, добавлять отключенный атрибут к флажкам вместо глобальной переменной блокировки? Ну, глобальные блокировки могут быть несколько подвержены ошибкам, но более того, у нас уже есть глобальный объект, который имеет значение в DOM. Если мы просто изменим состояние DOM, мы получим правильное поведение и сигнализируем нашим пользователям, что они должны очищаться от флажков до тех пор, пока поиск не завершится.

Тем не менее, вероятно, имеет смысл с любым сценарием блокировки/несвязывания, чтобы указать пользователю с помощью счетчика загрузки или того, что вы делаете.

Ответ 2

Вы можете использовать шаблон блокировки:

http://jsfiddle.net/RU6gL/

HTML

<input type="checkbox" onclick="fire()" >CB1
<br />
<input type="checkbox" onclick="fire()" >CB2

JS

function_lock = false

fire = function() {
    // First, check the lock isn't already reserved. If it is, leave immediately.
    if (function_lock) return;

    // We got past the lock check, so immediately lock the function to 
    // stop others entering
    function_lock = true;

    console.log("This message will appear once, until the lock is released")

    // Do your work. I use a simple Timeout. It could be an Ajax call.
    window.setTimeout(function() {
        // When the work finishes (eg Ajax onSuccess), release the lock.
        function_lock = false;
    }, 2000);
}

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

Этот шаблон довольно приятный, потому что он дает вам возможность управления, когда вы освобождаете блокировку, вместо того, чтобы полагаться на временной интервал, например "debounce". Например, он будет работать с Ajax. Если ваш флажок запускает вызов Ajax для фильтрации, вы можете:

  • При первом щелчке установите блокировку
  • Вызов конечной точки Ajax. Последующие клики не будут вызывать конечную точку Ajax.
  • В функции успеха Ajax reset заблокирован.
  • Теперь флажки можно снова щелкнуть.

HTML

<input type="checkbox" onclick="doAjax()" >CB2

JS

ajax_lock = false

doAjax: function() {
    // Check the lock.
    if (ajax_lock) return;

    // Acquire the lock.
    ajax_lock = true;

    // Do the work.
    $.get("url to ajax endpoint", function() {
         // This is the success function: release the lock
         ajax_lock = false;
    });   
} 

Ответ 3

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

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

Вот простой пример использования jquery для повторного включения флажка после некоторой обработки http://jsfiddle.net/94coc8sd/

со следующим кодом:

function processStuff() {
    var dfd = $.Deferred();

    // do some processing, when finished, 
    // resolve the deferred object
    window.setTimeout(function(){
        dfd.resolve();
    }, 2000);

    return dfd.promise();
}

function startProcessing() {
    $('#processingCheckbox').attr('disabled', 'disabled');
     var promise = processStuff();    
    promise.done(enableCheckbox);
}

function enableCheckbox() {
    $('#processingCheckbox').removeAttr('disabled');
}

$('#processingCheckbox').on('click', startProcessing);