From 69cb59c70835ea42b1a46d11c2dc8fae732aa680 Mon Sep 17 00:00:00 2001 From: loonlylokly Date: Sun, 18 Aug 2024 12:53:42 +0300 Subject: [PATCH 1/3] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D1=8F=D0=B5=D1=82=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D1=8E?= =?UTF-8?q?=20debounce?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/debounce/demos/debounced-search/index.html | 15 ++++-------- js/debounce/index.md | 24 ++++++++++--------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/js/debounce/demos/debounced-search/index.html b/js/debounce/demos/debounced-search/index.html index 7e02e58d2a..e6c94a51be 100644 --- a/js/debounce/demos/debounced-search/index.html +++ b/js/debounce/demos/debounced-search/index.html @@ -164,16 +164,11 @@ const searchResults = document.querySelector('.search-results') function debounce(callee, timeoutMs) { - return function perform(...args) { - let previousCall = this.lastCall - this.lastCall = Date.now() - - if (previousCall && ((this.lastCall - previousCall) <= timeoutMs)) { - clearTimeout(this.lastCallTimer) - } - - this.lastCallTimer = setTimeout(() => callee(...args), timeoutMs) - } + let timer; + return (...args) => { + clearTimeout(timer); + timer = setTimeout(() => { callee.apply(this, args); }, timeoutMs); + }; } function handleInput(e) { diff --git a/js/debounce/index.md b/js/debounce/index.md index 8e1bf09a0e..bdc65f08dd 100644 --- a/js/debounce/index.md +++ b/js/debounce/index.md @@ -233,23 +233,25 @@ const server = { Итак, `debounce()` — это функция высшего порядка, принимающая аргументом функцию, которую надо «отложить». -Поехали. Аргументами будут функция, которую надо «откладывать», и интервал времени, спустя который следует вызывать функцию. Как результат возвращаем другую функцию. Это нужно, чтобы мы могли не менять другие части кода. Чуть позже увидим, как это помогает. В переменной `previousCall` мы храним временную метку предыдущего вызова, а в переменной текущего вызова — временную метку нынешнего момента. Это нужно, чтобы потом сравнить, когда функция была вызвана в этот раз и в предыдущий. Если разница между вызовами меньше, чем указанный интервал, то мы очищаем таймаут, который отвечает за непосредственно вызов функции-аргумента. Обратите внимание, что мы передаём все аргументы `...args`, которые получаем в функции `perform()`. Это тоже нужно, чтобы не приходилось менять другие части кода. Если таймаут был очищен, вызова не произойдёт. Если он не был очищен, то вызовется `callee`. Таким образом, мы как бы «отодвигаем» вызов `callee` до тех пор, пока «снаружи всё не подуспокоится». +Поехали. Аргументами будут функция, которую надо «откладывать», и интервал времени, спустя который следует вызывать функцию. Как результат возвращаем другую функцию. Это нужно, чтобы мы могли не менять другие части кода. Чуть позже увидим, как это помогает. + +Обратите внимание, что мы передаём все аргументы `...args`, которые получаем в возвращаемой стрелочной функции. Это тоже нужно, чтобы не приходилось менять другие части кода. Если таймаут был очищен, вызова не произойдёт. Если он не был очищен, то вызовется `callee`. Таким образом, мы как бы «отодвигаем» вызов `callee` до тех пор, пока «снаружи всё не подуспокоится». ```javascript function debounce(callee, timeoutMs) { - return function perform(...args) { - let previousCall = this.lastCall + let timer; + return (...args) => { + clearTimeout(timer); + timer = setTimeout(() => { callee.apply(this, args); }, timeoutMs); + }; +} +``` - this.lastCall = Date.now() +Как работает стрелочная функция, которую возвращает `debounce`: - if (previousCall && this.lastCall - previousCall <= timeoutMs) { - clearTimeout(this.lastCallTimer) - } +1. При вызове функции, возвращаемой debounce, сначала выполняется `clearTimeout(timer)`. Это удаляет ранее установленный таймер, если он существует. Это необходимо, чтобы предотвратить выполнение предыдущего вызова функции `callee`, если новый вызов произошел до завершения задержки. - this.lastCallTimer = setTimeout(() => callee(...args), timeoutMs) - } -} -``` +1. Затем устанавливается новый таймер с помощью setTimeout, и ссылка на этот таймер сохраняется в переменной timer. Использовать такой `debounce()` мы можем так: From 22cbcf49202401a528b854654b351d876f65f043 Mon Sep 17 00:00:00 2001 From: loonlylokly Date: Mon, 26 Aug 2024 21:14:21 +0300 Subject: [PATCH 2/3] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D1=8F=D0=B5=D1=82=20debounce,=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D1=8F=D0=B5=D1=82=20=D0=BE=D0=B1=D1=8A=D1=8F=D1=81=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/debounce/demos/debounced-search/index.html | 6 ++--- js/debounce/index.md | 23 ++++++++++++------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/js/debounce/demos/debounced-search/index.html b/js/debounce/demos/debounced-search/index.html index e6c94a51be..2ca1dca1e6 100644 --- a/js/debounce/demos/debounced-search/index.html +++ b/js/debounce/demos/debounced-search/index.html @@ -163,11 +163,11 @@ const searchInput = searchForm.querySelector('[type="search"]') const searchResults = document.querySelector('.search-results') - function debounce(callee, timeoutMs) { + function debounce(callback, delay) { let timer; - return (...args) => { + return function perform(...args) { clearTimeout(timer); - timer = setTimeout(() => { callee.apply(this, args); }, timeoutMs); + timer = setTimeout(() => callback.apply(this, args), delay); }; } diff --git a/js/debounce/index.md b/js/debounce/index.md index bdc65f08dd..71b11394cf 100644 --- a/js/debounce/index.md +++ b/js/debounce/index.md @@ -233,25 +233,32 @@ const server = { Итак, `debounce()` — это функция высшего порядка, принимающая аргументом функцию, которую надо «отложить». -Поехали. Аргументами будут функция, которую надо «откладывать», и интервал времени, спустя который следует вызывать функцию. Как результат возвращаем другую функцию. Это нужно, чтобы мы могли не менять другие части кода. Чуть позже увидим, как это помогает. +Поехали. Аргументами будут функция, которую надо «откладывать» (`callback`), и интервал времени, спустя который следует вызывать функцию (`delay`). Как результат возвращаем другую функцию, которая является оберткой над `setTimeout` с переданной `callback` функцией. -Обратите внимание, что мы передаём все аргументы `...args`, которые получаем в возвращаемой стрелочной функции. Это тоже нужно, чтобы не приходилось менять другие части кода. Если таймаут был очищен, вызова не произойдёт. Если он не был очищен, то вызовется `callee`. Таким образом, мы как бы «отодвигаем» вызов `callee` до тех пор, пока «снаружи всё не подуспокоится». +Обратите внимание, что мы передаём все аргументы `...args`, которые получаем в возвращаемой функции `perform`. Это нужно, чтобы передавать функцию `callback` с любыми аргументами. Если таймаут был очищен, вызова не произойдёт. Если он не был очищен, то вызовется `callback`. Таким образом, мы как бы «отодвигаем» вызов `callback` до тех пор, пока «снаружи всё не подуспокоится». ```javascript -function debounce(callee, timeoutMs) { +function debounce(callback, delay) { let timer; - return (...args) => { + return function perform(...args) { clearTimeout(timer); - timer = setTimeout(() => { callee.apply(this, args); }, timeoutMs); + timer = setTimeout(() => { callback.apply(this, args); }, delay); }; } ``` -Как работает стрелочная функция, которую возвращает `debounce`: +Как работает функция `perform`: -1. При вызове функции, возвращаемой debounce, сначала выполняется `clearTimeout(timer)`. Это удаляет ранее установленный таймер, если он существует. Это необходимо, чтобы предотвратить выполнение предыдущего вызова функции `callee`, если новый вызов произошел до завершения задержки. +1. При вызове функции `perform`, сначала выполняется `clearTimeout(timer)`. Так удаляется ранее установленный таймер, если он существует. Это необходимо, чтобы предотвратить выполнение предыдущего вызова функции `callback`, если новый вызов произошёл до завершения задержки. + +1. Затем устанавливается новый таймер с помощью `setTimeout`, и ссылка на этот таймер сохраняется в переменной `timer`. + +1. В `setTimeout` первым аргументом передается стрелочная функция с вызовом нашего `callback` c привязкой контектса и передачей всех аргументов. Вторым аргументом передается задержка `delay`. + +Важно отметить, несколько моментов: +- возвращаемая функция `perform` НЕ должна быть стрелочной, чтобы не терялся контекст. +- чтобы `callback` функция передаваемая в `setTimeout` не потеряла контекст его нужно привязать с помощью `apply`. Это важно при работе с обработчиком событий браузера. -1. Затем устанавливается новый таймер с помощью setTimeout, и ссылка на этот таймер сохраняется в переменной timer. Использовать такой `debounce()` мы можем так: From 6e7abf3c5e902f030ac6371717e11656206d1610 Mon Sep 17 00:00:00 2001 From: Tatiana Fokina Date: Sun, 22 Sep 2024 00:44:50 +0400 Subject: [PATCH 3/3] =?UTF-8?q?=D0=A1=D0=BB=D0=B5=D0=B3=D0=BA=D0=B0=20?= =?UTF-8?q?=D1=80=D0=B5=D0=B4=D0=B0=D1=87=D0=B8=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/debounce/index.md | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/js/debounce/index.md b/js/debounce/index.md index 71b11394cf..6b9605fe98 100644 --- a/js/debounce/index.md +++ b/js/debounce/index.md @@ -239,28 +239,26 @@ const server = { ```javascript function debounce(callback, delay) { - let timer; + let timer return function perform(...args) { - clearTimeout(timer); - timer = setTimeout(() => { callback.apply(this, args); }, delay); - }; + clearTimeout(timer) + timer = setTimeout(() => { callback.apply(this, args) }, delay) + } } ``` Как работает функция `perform`: 1. При вызове функции `perform`, сначала выполняется `clearTimeout(timer)`. Так удаляется ранее установленный таймер, если он существует. Это необходимо, чтобы предотвратить выполнение предыдущего вызова функции `callback`, если новый вызов произошёл до завершения задержки. +1. Устанавливается новый таймер с помощью `setTimeout`, и ссылка на этот таймер сохраняется в переменной `timer`. +1. В `setTimeout` первым аргументом передаётся стрелочная функция с вызовом нашего `callback` c привязкой контектса и передачей всех аргументов. Вторым аргументом передаётся задержка `delay`. -1. Затем устанавливается новый таймер с помощью `setTimeout`, и ссылка на этот таймер сохраняется в переменной `timer`. +Отметим несколько важных моментов: -1. В `setTimeout` первым аргументом передается стрелочная функция с вызовом нашего `callback` c привязкой контектса и передачей всех аргументов. Вторым аргументом передается задержка `delay`. +- возвращаемая функция `perform` НЕ должна быть стрелочной, чтобы не терялся контекст; +- чтобы `callback` функция, передаваемая в `setTimeout`, не потеряла контекст, его нужно привязать с помощью `apply`. Это важно при работе с обработчиком событий браузера. -Важно отметить, несколько моментов: -- возвращаемая функция `perform` НЕ должна быть стрелочной, чтобы не терялся контекст. -- чтобы `callback` функция передаваемая в `setTimeout` не потеряла контекст его нужно привязать с помощью `apply`. Это важно при работе с обработчиком событий браузера. - - -Использовать такой `debounce()` мы можем так: +Использовать `debounce()` мы можем так: ```javascript // Функция, которую хотим «откладывать» @@ -280,7 +278,7 @@ debouncedDoSomething(42) ## Применяем `debounce()` -Теперь мы можем применить `debounce()` в нашем обработчике. Сперва немного порефакторим. Вынесем обработчик события в отдельную функцию. Внутри она будет такой же, но так нам удобнее оборачивать её в `debounce()`. +Теперь применим `debounce()` в нашем обработчике. Сперва немного порефакторим. Вынесем обработчик события в отдельную функцию. Внутри она будет такой же, но так нам удобнее оборачивать её в `debounce()`. ```javascript function handleInput(e) { @@ -300,7 +298,7 @@ function handleInput(e) { searchInput.addEventListener('input', handleInput) ``` -Теперь обернём вынесенную функцию и обновим `addEventListener`. Укажем, что нам нужно ждать 250 мс, прежде чем запустить обработчик. Дальше передаём новую `debounced`-функцию в `addEventListener`. +Обернём вынесенную функцию и обновим `addEventListener`. Укажем, что нам нужно ждать 250 мс, прежде чем запустить обработчик. Дальше передаём новую `debounced`-функцию в `addEventListener`. ```javascript function handleInput(e) { @@ -318,12 +316,10 @@ searchInput.addEventListener('input', debouncedHandle) Вместо пяти запросов теперь отправляем всего один! -Обратите внимание, что API функции не поменялось. Мы как передавали [`event`](/js/event/), так и передаём. То есть для внешнего мира debounced-функция ведёт себя точно так же, как и простая функция-обработчик. - -Это удобно, потому что меняется лишь одна небольшая часть программы, не затрагивая системы в целом. +Обратите внимание, что API функции не поменялось. Мы как передавали [`event`](/js/event/), так и передаём. То есть для внешнего мира debounced-функция ведёт себя точно так же, как и простая функция-обработчик. Это удобно, потому что меняется лишь одна небольшая часть программы, не затрагивая системы в целом. ### Результат Полный пример строки поиска у нас получится такой: - +