jQuery/backbone.js — задержка вызова функции

У меня есть элемент #search, который при возникновении события keyup должен запускать функцию. Эта функция должна срабатывать только в том случае, если keyup не произошло в течение установленного периода времени (например, 500 миллисекунд). Это предотвратит обновление результатов поиска при каждой нажатой букве. Проблема в том, что с backbone.js у меня есть события в хэше, и тот, который применим, выглядит так:

'keyup #search' : 'setSearch'

которая вызывает функцию setSearch() при возникновении события keyup. Я не совсем понимаю, как с этим справиться на данный момент. Я пробовал разные вещи, но ничто не может поддерживать таймер после завершения функции.

У меня есть что-то вроде этого:

setSearch: function(event) {
            var timer = window.setTimeout( function() {
                // run function here
                alert('fired');
            }, 500);
    },

вместо alert('fired') я запущу свою собственную функцию. Я понимаю, почему этот код не работает (таймер устанавливается для каждого происходящего события keyup. Но у меня до сих пор нет четкого представления о том, что еще я мог бы попробовать.


person Matthew    schedule 20.07.2011    source источник


Ответы (4)


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

setSearch: function(event) {
    var self = this;
    if(self.timer)
        clearTimeout(self.timer);
    self.timer = setTimeout(function() {
        alert('fired');
        self.timer = null;
    }, 500);
}

Итак, если таймер уже запущен, вы вызываете clearTimeout чтобы остановить его, запустите новый таймер и сохраните идентификатор таймера в self.timer (AKA this.timer). Вы также захотите сбросить сохраненный идентификатор таймера в функции обратного вызова таймера, иначе ваш setSearch ничего не сделает после того, как его таймер сработает один раз. И все self дело заключается в том, чтобы захватить this для использования в функции обратного вызова таймера.

person mu is too short    schedule 20.07.2011

То, что вы ищете, на самом деле является функцией, предоставленной вам из underscore.js (требование Backbone).

 setSearch: _.throttle(function() {
                //Do Stuff
              }, 500),

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

Дополнительная информация: http://documentcloud.github.com/underscore/#throttle

person Skylar Anderson    schedule 23.08.2011
comment
Комментарий пользователя 1243645: я столкнулся с подобным требованием в своем проекте. Я просто хотел добавить, в ответ на сообщение Скайлар Андерсон о _.throttle, я обнаружил, что _.debounce()< /a> работает лучше для моих нужд. - person Peter O.; 02.03.2012
comment
Дебунс намного лучше, чем дроссель для этой проблемы. - person tonyhb; 07.09.2012

Предотвращение обновления результатов поиска при каждом keyup — это именно та ситуация, для которой предназначена функция Underscore _.debounce(function, wait). В документации по подчеркиванию для _.debounce() указано:

Создает и возвращает новую отклоненную версию переданного function, выполнение которой будет отложено до тех пор, пока не пройдет wait миллисекунд с момента последнего вызова. Полезно для реализации поведения, которое должно произойти только после того, как входные данные перестанут поступать.

Ваш рефакторинговый код будет выглядеть так же просто, как:

setSearch: function(event) {
    _.debounce(doSomething, 300);
},
person Walter Roman    schedule 09.09.2014
comment
который отложит его выполнение до тех пор, пока не истечет миллисекунды ожидания с момента последнего вызова - не работает в случае "поля поиска", потому что вы не хотите, чтобы он выполнял поиск при первом нажатии, вы хотите ждать 3 нажатия клавиш и т. д., прежде чем выполнять поиск - особенно для больших наборов. А вот в случае возгорания чего-то потом ждать снова пожар, да это здорово. - person VeenarM; 09.06.2015

Поскольку вы хотите, чтобы ваши события обработчика событий могли поддерживать, имеет ли событие recentlyFired, вы, вероятно, захотите обернуть свой обработчик замыканием и сохранить этот статус. Статус должен быть изменен на true, когда событие сработало, и сброшен на false после задержки в 500 мс.

setSearch: function( ) {
    var firedRecently = false;
    return function(event) {
        if (firedRecently) {
            // it has fired recently. Do you want to do something here?
        } else {
            // not fired recently
            firedRecently = true;
            // run your function here
            alert('fired');
            var resetStatus = window.setTimeout( function () {
                firedRecently = false;
            }, 500);
        }
    }
}( );
person achow    schedule 20.07.2011