Меня интересует функция «debouncing» в javascript, написанная здесь: http://davidwalsh.name/javascript-debounce-function
К сожалению, код недостаточно четко объяснен для меня, чтобы понять. Может кто-нибудь помочь мне разобраться, как это работает (я оставил свои комментарии ниже). Короче я просто очень не понимаю как это работает
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds.
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
РЕДАКТИРОВАТЬ: скопированный фрагмент кода ранее был callNow
в неправильном месте.
javascript
debouncing
Startec
источник
источник
clearTimeout
с чем-то, что не является действительным идентификатором таймера, он ничего не делает.WindowTimers
объекта, для которого был вызван метод, метод ничего не делает».Ответы:
Код в вопросе был немного изменен по сравнению с кодом в ссылке. В ссылке есть проверка
(immediate && !timeout)
ДО создания нового тайм-аута. После этого немедленный режим никогда не срабатывает. Я обновил свой ответ, чтобы аннотировать рабочую версию по ссылке.источник
immediate && timeout
проверки. Не всегда будетtimeout
(потому чтоtimeout
называется раньше). Кроме того, что хорошего в том,clearTimeout(timeout)
что когда он объявляется (делает его неопределенным) и очищается раньшеimmediate && !timeout
Проверка когда дребезг сконфигурирован сimmediate
флагом. Это выполнит функцию немедленно, но установитwait
тайм-аут раньше, если может быть выполнено снова. Таким образом,!timeout
часть в основном говорит: «Извините, Буб, это уже было выполнено в определенном окне» ... помните, что функция setTimeout очистит его, позволив выполнить следующий вызов.setTimeout
функции? Кроме того, я попробовал этот код, для меня, передачаtrue
для немедленного просто предотвращает вызов функции вообще (а не вызывается после задержки). Это случилось для вас?Здесь важно отметить, что
debounce
создается функция, которая «закрывается» надtimeout
переменной. Вtimeout
переменной остается доступным при каждом вызове функции производится даже после того, какdebounce
сам вернулся, и может меняться в течение различных вызовов.Общая идея
debounce
заключается в следующем:Первый пункт справедлив
var timeout;
, это действительно справедливоundefined
. К счастью,clearTimeout
это довольно слабо в отношении ввода: передачаundefined
идентификатора таймера заставляет его просто ничего не делать, он не выдает ошибку или что-то в этом роде.Второй пункт сделан произведенной функцией. Сначала он хранит некоторую информацию о вызове (
this
контекст иarguments
) в переменных, чтобы затем использовать их для отклоненного вызова. Затем он очищает тайм-аут (если был один набор), а затем создает новый, чтобы заменить его, используяsetTimeout
. Обратите внимание, что это перезаписывает значение,timeout
и это значение сохраняется в течение нескольких вызовов функций! Это позволяет debounce фактически работать: если функция вызывается несколько раз,timeout
она перезаписывается несколько раз новым таймером. Если бы это было не так, то несколько вызовов могут вызвать несколько таймеров , чтобы быть запущен , которые все остаются активными - звонки будут просто задерживаются, но не подавление дребезга контактов.Третий пункт делается в обратном вызове тайм-аута. Он сбрасывает
timeout
переменную и выполняет фактический вызов функции, используя сохраненную информацию о вызове.Предполагается, что
immediate
флаг контролирует, должна ли функция вызываться до или после таймера. Если этоfalse
, исходная функция не не вызывается , пока после того, как таймер хит. Если это такtrue
, исходная функция вызывается первой и больше не будет вызываться, пока не будет нажата таймер.Тем не менее, я считаю, что
if (immediate && !timeout)
проверка неверна:timeout
только что был установлен идентификатор таймера, возвращаемыйsetTimeout
так!timeout
, всегдаfalse
в этой точке, и, следовательно, функция никогда не может быть вызвана. Текущая версия underscore.js, кажется, имеет немного другую проверку, где она оцениваетimmediate && !timeout
перед вызовомsetTimeout
. (Алгоритм также немного отличается, например, он не используетclearTimeout
.) Вот почему вы всегда должны стараться использовать последнюю версию ваших библиотек. :-)источник
!timeout
в конце? Почему он не существует всегда (потому что он установленsetTimeout(function() etc.)
debounce
, да, но оно распределяется между вызовами возвращаемой функции (той функции, которую вы собираетесь использовать). Так , например, вg = debounce(f, 100)
значенииtimeout
сохраняется в течение нескольких звонковg
.!timeout
Проверка в конце концов , это ошибка , которую я верю, и это не в текущем underscore.js коды.null
. В моих тестах с приведенным выше кодом установка немедленного значения в true делает функцию вообще не вызываемой, как вы упомянули. Любое решение без подчеркивания?Отклоненные функции не выполняются при вызове, они ждут паузу вызовов в течение настраиваемой продолжительности перед выполнением; каждый новый вызов перезапускает таймер.
Дросселированные функции выполняются, а затем ждут настраиваемую длительность, прежде чем снова смогут запускаться.
Debounce отлично подходит для событий нажатия клавиш; когда пользователь начинает печатать, а затем приостанавливает, вы отправляете все нажатия клавиш как одно событие, таким образом сокращая количество вызовов обработки.
Throttle отлично подходит для конечных точек в реальном времени, которые вы хотите разрешить пользователю вызывать только один раз за определенный период времени.
Проверьте Underscore.js для их реализации тоже.
источник
Я написал пост под названием « Демистификация Debounce в JavaScript», где я объясняю, как именно работает функция debounce, и включаю демонстрацию.
Я тоже не до конца понимал, как работает функция debounce, когда я впервые столкнулся с ней. Хотя они относительно небольшие по размеру, они на самом деле используют довольно продвинутые концепции JavaScript! Хорошее управление прицелом, замыканиями и
setTimeout
методом поможет.С учетом вышесказанного ниже приведена базовая функция debounce, которая была объяснена и продемонстрирована в моем посте, указанном выше.
Готовый продукт
Объяснение
источник
Что вы хотите сделать, это следующее: если вы пытаетесь вызвать функцию сразу за другой, первая должна быть отменена, а новая должна подождать заданное время ожидания и затем выполнить. Таким образом, в действительности вам нужен способ отменить таймаут первой функции? Но как? Вы можете вызвать функцию и передать возвращаемый таймаут-идентификатор, а затем передать этот идентификатор в любые новые функции. Но решение, приведенное выше, более элегантно.
Что он делает, так это делает
timeout
переменную доступной в области возвращаемой функции. Поэтому, когда происходит событие «resize», оно больше не вызываетсяdebounce()
, следовательно,timeout
содержимое не изменяется (!) И все еще доступно для «следующего вызова функции».Ключевым моментом здесь является то, что мы вызываем внутреннюю функцию каждый раз, когда происходит событие изменения размера. Возможно, будет более понятно, если мы представим, что все события resize находятся в массиве:
Вы видите, что
timeout
доступно для следующей итерации? И нет никаких причин, по - моему переименованthis
вcontent
иarguments
кargs
.источник
this
иarguments
изменения внутри функции обратного вызова setTimeout (). Вы должны сохранить копию в другом месте или эта информация будет потеряна.Это вариант, который всегда запускает дебатированную функцию при первом вызове с более описательно названными переменными:
источник
Простой метод Debounce в JavaScript
Пример выполнения JSFiddle: https://jsfiddle.net/arbaazshaikh919/d7543wqe/10/
источник
Простая функция debounce: -
HTML: -
Javascript: -
источник