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

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

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

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

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

3 ответов


вы хотите обернуть свой 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 там, и писать свой собственный не имеет большого значения, если вы не можете или не хотите включать подчеркивание.js.

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

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

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, добавьте атрибут disabled в флажки вместо глобальной переменной блокировки? Ну, глобальные блокировки могут быть несколько подвержены ошибкам, но более того, у нас уже есть глобальный объект, который имеет значение в DOM. Если мы просто изменим состояние DOM, мы получим правильное поведение и подадим сигнал нашим пользователям, что они должны расслабиться на флажках до завершения поиска.

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


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

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 секунды по таймауту.

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

  1. при первом щелчке установите блокировку
  2. вызовите конечную точку Ajax. Последующие клики не будут вызывать конечную точку Ajax.
  3. в функции успеха Ajax сбросьте блокировку.
  4. флажки теперь можно щелкнуть снова.

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

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

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

вот простой пример использования jQuery promise для повторного включения флажка после некоторых обработка 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);