Пояснення розмови - Як змусити JavaScript чекати, поки користувач закінчить друкувати

Функції розв'язування в JavaScript - це функції вищого порядку, які обмежують швидкість виклику іншої функції.

Функція вищого порядку - це функція, яка або приймає функцію як аргумент, або повертає функцію як частину свого оператора return. Наша функція розриву робить і те, і інше.

Найбільш поширеним варіантом використання розриву є передача його як аргументу слухачеві події, приєднаному до елемента HTML. Щоб краще зрозуміти, як це виглядає і чому це корисно, давайте розглянемо приклад.

Скажімо, у вас є функція з іменем, myFuncяка викликається кожного разу, коли ви щось вводите у поле введення. Ознайомившись із вимогами до вашого проекту, ви вирішили, що хочете змінити досвід.

Натомість ви хочете myFuncвиконати, коли минуло принаймні 2 секунди з моменту останнього введення.

Ось де розмова може вступити в гру. Замість того, myFuncщоб переходити до слухача події, ви переходите до розмови. Тоді розв'язка сприймається myFuncяк аргумент разом із числом 2000.

Тепер кожен раз, коли ви натискаєте кнопку, myFuncвиконується лише в тому випадку, якщо минуло не менше 2 секунд до того, як myFuncбуло викликано останній раз .

Як реалізувати функцію розриву

Від початку до кінця потрібно лише 7 рядків коду, щоб реалізувати функцію зняття звуку. Решта цього розділу зосереджена на цих 7 рядках коду, щоб ми могли побачити, як наша функція дебансу працює внутрішньо.

function debounce( callback, delay ) { let timeout; return function() { clearTimeout( timeout ); timeout = setTimeout( callback, delay ); } }

Починаючи з рядка 1, ми оголосили нову функцію з назвою debounce. Ця нова функція має два параметри, callbackі delay.

function debounce( callback, delay ) { } 

callback - це будь-яка функція, якій потрібно обмежити кількість разів її виконання.

delay- це час (у мілісекундах), який повинен пройти, перш ніж callbackможна виконати знову.

function debounce( callback, delay ) { let timeout; }

У рядку 2 ми оголошуємо неініціалізовану змінну з іменем timeout.

Ця нова змінна містить timeoutIDповернене, коли ми setTimeoutпізніше звертаємось до нашої debounceфункції.

function debounce( callback, delay ) { let timeout; return function() { } }

У рядку 3 ми повертаємо анонімну функцію. Ця анонімна функція закриється над timeoutзмінною, щоб ми могли зберегти доступ до неї навіть після завершення початкового виклику до debounce.

Закриття в JavaScript відбувається, коли внутрішня функція зберігає доступ до лексичного обсягу своєї зовнішньої функції, навіть якщо зовнішня функція завершила своє виконання. Якщо ви хочете дізнатись більше про закриття, ви можете прочитати розділ 7 "Ви не знаєте JS" Кайла Сімпсона
function debounce( callback, delay ) { let timeout; return function() { clearTimeout( timeout ); } }

У рядку 4 ми називаємо clearTimeoutметод WindowOrWorkerGlobalScopeзмішування. Це забезпечить, щоб кожен раз, коли ми викликаємо нашу debounceфункцію, timeoutбуло скинуто, і лічильник може запускатися знову.

WindowOrWorkerGlobalScopeMixin з JavaScript дає нам доступ до кількох добре відомих способів, як setTimeout, clearTimeout, setInterval, clearIntervalі fetch.

Ви можете дізнатися більше про це, прочитавши цю статтю.

function debounce( callback, delay ) { let timeout; return function() { clearTimeout( timeout ); timeout = setTimeout( callback, delay ); } }

У рядку 5 ми досягли кінця реалізації нашої debounceфункції.

Цей рядок коду робить кілька речей. Перша дія - це присвоєння значення timeoutзмінній, яку ми оголосили в рядку 2. Значення - це timeoutIDте, яке повертається, коли ми викликаємо setTimeout. Це дозволить нам посилатися на час очікування, створений за допомогою виклику, setTimeoutщоб ми могли скинути його кожного разу, коли використовується наша debounceфункція.

Друга виконана дія - дзвінок setTimeout. Це створить час очікування, який буде виконуватися callback(аргумент функції, переданий нашій debounceфункції) після того, як delay(аргумент числа, переданий нашій debounceфункції), минув.

Оскільки ми використовуємо тайм-аут, callbackбуде виконуватися лише в тому випадку, якщо ми дозволимо тайм-ауту досягти 0. Саме тут debounceпочинає діяти суть нашої функції, оскільки ми скидаємо тайм-аут кожного разу, коли debounceвикликається. Саме це дозволяє нам обмежувати швидкість виконання myFunc.

Рядки 5 і 6 містять лише дужки, тому ми не будемо їх переглядати.

Це воно. Саме так наша debounceфункція працює внутрішньо. Тепер додамо наш попередній приклад із самого початку. Ми збираємося створити поле введення та приєднати прослуховувач подій з нашою debounceфункцією як один з аргументів.

Приклад із реального світу

По-перше, нам потрібно створити поле введення.

Type something in! 

Далі нам потрібно створити функцію, яку ми хочемо виконувати щоразу, коли ми вводимо щось у поле введення.

function helloWorld() { console.log("Hello World!") }

Нарешті, нам потрібно вибрати поле введення, яке ми створили вище, і приєднати keyupдо нього прослуховувач події.

const myInput = document.getElementById("myInput"); myInput.addEventListener( "keyup", debounce( helloWorld, 2000 ) );

На цьому наш реальний приклад завершується! Кожен раз, коли ми вводимо щось у поле введення, helloWorldбуде виконуватися, якщо минуло принаймні 2 секунди з моменту останнього введення.

Окрема подяка користувачеві Stratoscope Reddit за допомогу у виправленні деяких початкових кодів у цій статті. Ось робоча демонстрація, яку він створив для цієї debounceфункції на Repl.it.

Заключні примітки

Функції розв'язування - це прості, але потужні функції, які можуть помітно вплинути на більшість програм JavaScript.

Хоча наш приклад був веселим і зрозумілим, багато великих організацій використовують функції розриву для підвищення продуктивності своїх додатків.

If you want to learn more about JavaScript, check out my website! I am working on some cool stuff at //juanmvega.com.