Как закодировать устранение дребезга и дросселирование в TypeScript
В некоторых руководствах по интерфейсу вы, возможно, слышали о дебаунсинге и троттлинге, так в каких случаях они используются? Зачем это использовать?
На самом деле, все они предназначены для предотвращения возможных проблем с производительностью при высокочастотных операциях.
Отказ будет выполняться только один раз в течение N
секунд после инициирующего события, и если он будет запущен снова в течение N
секунд, отсчет времени начнется заново.
Вот код JavaScript:
const debounce = (func, ms) => { let timer; return (...args) => { if (timer) clearTimeout(timer); timer = setTimeout(() => { func(...args); }, ms); }; };
Здесь мы разумно используем замыкания, сохраняем возвращаемое значение setTimeout
в замыкании, а затем возвращаем новую функцию. Когда эта новая функция вызывается часто, она проверяет, существует ли действительный timer
, и если да, очищает последний таймер, а затем регенерирует таймер.
Обратите внимание, что функция, которую мы возвращаем, является стрелочной функцией, что означает, что ее this
не изменяется, поэтому, когда мы вызываем func
, она также вызывается напрямую. Если вы хотите изменить точку исходной функции this
при вызове, вы можете сделать это:
const debounce = (func, ms) => { let timer; return function (...args) { if (timer) clearTimeout(timer); timer = setTimeout(() => { func.apply(this, ...args); }, ms); }; };
Глядя на приведенный выше код, мы возвращаем традиционную функцию, что означает, что ее this
определяется на основе того, как вы ее вызываете. Затем мы используем func.apply(this, ...args);
, чтобы передать это this
исходной функции. Но обратите внимание, что если ваша исходная функция является стрелочной, то это не работает.
Подводя итог, я бы рекомендовал использовать первый способ и использовать стрелочные функции для определения исходной функции. Таким образом, this
указывает на все функции, и ваш код становится более кратким и понятным.
Вот TypeScript с небольшим добавлением магии:
const debounce = <F extends (...args: any[]) => void>(func: F, ms: number) => { let timer: ReturnType<typeof setTimeout>; return (...args: Parameters<F>) => { if (timer) clearTimeout(timer); timer = setTimeout(() => { func(...args); }, ms); }; };
Далее поговорим о троттлинге, он будет выполняться только один раз в N
секунд, и не повлияет на повторный запуск в течение N
секунд. То есть просто разбавляет частоту исполнения.
const throttle = (func, ms) => { let timer; return (...args) => { if (timer) return; timer = setTimeout(() => { func(...args); timer = null; }, ms); }; };
Можно видеть, что разница между ним и debounce заключается в том, что функция завершится, если есть действительный таймер, а debounce должен очистить последний таймер.
Проблема this
тоже такая же, поэтому я не буду повторяться здесь, но рекомендуется использовать стрелочные функции.
Вот TypeScript с небольшим добавлением магии:
const throttle = <F extends (...args: any[]) => void>(func: F, ms: number) => { let timer: ReturnType<typeof setTimeout> | null; return (...args: Parameters<F>) => { if (timer) return; timer = setTimeout(() => { func(...args); timer = null; }, ms); }; };
Наконец, давайте поговорим о том, в каких случаях вы можете их использовать. Отказ можно использовать в случае, когда редактор модифицируется в режиме реального времени, и синхронизация будет пересчитана, если произойдет модификация. Или при изменении размера окна браузера функция прослушивателя может устранить дребезг. Дросселирование можно использовать в событиях прослушивателя прокрутки браузера или событиях воспроизведения видео, например, рассчитывая каждые 1s
.
Не являетесь участником Medium? Поддержите меня здесь, став одним из них.
Спасибо за прочтение!
Дополнительные материалы на PlainEnglish.io. Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter, LinkedIn, YouTube и Discord.