Серия статей:
- Читать один модуль npm в день (1) — имя пользователя
- Читать один модуль npm в день (2) - mem
- Читать один модуль npm в день (3) — mimic-fn
Знание дескрипторов атрибутов, представленное в предыдущей статье, слишком теоретическое, и я прочитал его сегодня.throttle-debounceМодули будут намного практичнее и их можно будет часто использовать в работе.
вступление в одно предложение
Модуль npm для чтения сегодня:throttle-debounce,Это обеспечиваетthrottle
а такжеdebounce
Две функции: Throttle означает дросселирование, debounce означает антиджиттер, с помощью которого вы можете ограничить частоту выполнения функций и избежать проблем с производительностью, вызванных многократным выполнением функций за короткий промежуток времени Текущая версия пакета 2.0.1, скачать каждую неделю Сумма 63 000.
Применение
Первый выбор должен быть представленthrottle
а такжеdebounce
, все они могут быть использованы длярегулирование функцииЭто повышает производительность, но все же есть некоторые отличия:
- debounce: объединить события, которые запускаются несколько раз за короткий промежуток времени, в одно выполнение функции ответа на событие (часто выполняется при первом событии или при срабатывании последнего события), то есть только в течение этого периода времени.однаждыФактически выполнить функцию ответа на событие.
- дроссель: если одно и то же событие срабатывает несколько раз в течение короткого промежутка времени, функция реагирования на событие будет выполняться с меньшим интервалом времени, то есть это может быть возможно в течение этого промежутка времени.неоднократноВыполните функцию ответа на событие.
Хотя ожидание лифта занимает более десяти минут каждый день, вы все равно можете взять лифт в качестве примера:
- debounce: Если бы я был в лифте и собирался закрыть дверь, когда А хотел бы воспользоваться лифтом, я бы из вежливости нажал кнопку открытия двери, а затем попытался бы закрыть дверь после того, как он вошел в лифт; после того, как А вошел в лифт, обнаружил, что Б я тоже хочу подняться на лифте, потом опять из вежливости нажму на кнопку двери и буду ждать, пока он войдет в лифт. Поэтому, если кто-то все время хочет подняться на лифте, я буду продолжать откладывать время нажатия кнопки закрытия до тех пор, пока никто не захочет пользоваться лифтом (если я сделаю это в реальной жизни, я думаю, что ничего не смогу сделать, кроме как сесть на лифт). лифт каждый день.Сделано).
- дроссель: У меня на самом деле есть работа каждый день, невозможно бесконечно ждать кого-то в лифте. Так что на этот раз я буду немного более своевольным и подожду всего секунд 30. Неважно, захочет ли кто-нибудь подняться на лифте, я нажму кнопку закрытия и уйду.
Из приведенных выше двух примеров видно, что самая большая разница между ними заключается в том, что пока есть событие (кто-то хочет подняться на лифте), если вы используетеthrottle
метод, то функция ответа на событие будет выполнена в течение определенного периода времени (я нажимаю кнопку закрытия в течение 30 секунд); если используетсяdebounce
метод, то он будет выполнен только после того, как событие перестанет происходить (я обнаружил, что никто не хочет пользоваться лифтом).
Вы можете попробовать прокрутить мышь в следующей демонстрации, чтобы интуитивно почувствовать разницу между ними:
See the Pen The Difference Between Throttling, Debouncing, and Neither by Elvin Peng (@elvinn) on CodePen.
дляthrottle-debounce, его простое использование выглядит следующим образом:
import { throttle, debounce } from 'throttle-debounce';
function foo() { console.log('foo..'); }
function bar() { console.log('bar..'); }
const fooWrapper = throttle(200, foo);
for (let i = 1; i < 10; i++) {
setTimeout(fooWrapper, i * 30);
}
// => foo 执行了三次
// => foo..
// => foo..
// => foo..
const barWrapper = debounce(200, bar);
for (let i = 1; i < 10; i++) {
setTimeout(barWrapper, i * 30);
}
// => bar 执行了一次
// => bar..
Изучение исходного кода
реализация дроссельной заслонки
После упрощения исходного кода измените его следующим образом:
// 源码 4-1
function throttle(delay, callback) {
let timeoutID;
let lastExec = 0;
function wrapper() {
const self = this;
const elapsed = Number(new Date()) - lastExec;
const args = arguments;
function exec() {
lastExec = Number(new Date());
callback.apply(self, args);
}
clearTimeout(timeoutID);
if (elapsed > delay) {
exec();
} else {
timeoutID = setTimeout(exec, delay - elapsed);
}
}
return wrapper;
}
Логика всего кода очень понятна, всего три шага:
- Вычислить время, прошедшее с момента последнего выполнения функции
elapsed
, и сбрасывает ранее установленный таймер. - Если прошедшее время превышает установленный интервал
delay
, затем немедленно выполните функцию и обновите время выполнения самой последней функции. - Если прошедшее время меньше установленного интервала
delay
, затем черезsetTimeout
Настройте счетчик и включите функциюdelay - elapsed
Выполнить по прошествии времени.
Исходный код 4-1 не сложно понять, но нужно обратить вниманиеthis
использование:
function throttle(delay, callback) {
// ...
function wrapper() {
const self = this;
const args = arguments;
// ...
function exec() {
// ...
callback.apply(self, args);
}
}
}
В приведенном выше коде с помощьюself
временное хранение переменныхthis
значение, так что вexec
через функциюcallback.apply(self, args)
пройти в правильномthis
значение, этот подход вЗакрытиеОн очень часто используется в связанных вызовах функций. именно потому, что здесьthis
обработки, поэтому могут быть достигнуты следующие возможности:
function foo() { console.log(this.name); }
const fooWithName = throttle(200, foo);
const obj = {name: 'elvin'};
fooWithName.call(obj, 'elvin');
// => 'elvin'
реализация устранения ложных срабатываний
из-заdebounce
n просто задерживает время выполнения функции, у него нетthrottle
Возможность, которая гарантированно будет выполняться время от времени, поэтому ее проще реализовать:
function debounce(delay, callback) {
let timeoutID;
function wrapper() {
const self = this;
const args = arguments;
function exec() {
callback.apply(self, args);
}
clearTimeout(timeoutID);
timeoutID = setTimeout(exec, delay);
}
return wrapper;
}
Объедините приведенный выше код сthrottle
По сравнению с реализованным кодом можно обнаружить, что он удаленelapsed
Код после соответствующей логики, большая часть остального кода точно такая же, поэтомуdebounce
Функция может помочьthrottle
Реализация функцииthrottle-debounceЭто также сделано в исходном коде),throttle
функция также может использоватьdebounce
реализация функции.
Пример сценариев использования дросселя и устранения дребезга
throttle
а такжеdebounce
Он подходит для сценариев, когда пользователи часто выполняют одну и ту же операцию за короткий промежуток времени, например:
- Пользователь перетаскивает окно браузера, чтобы изменить размер окна, вызывая
resize
мероприятие. - Пользователь перемещает мышь, вызывая
mousemove
и т.д. события. - Пользователь вводит данные в поле ввода, вызывая
keydown
|keypress
|keyinput
|keyup
и т.д. события. - Пользователь прокручивает экран, вызывая
scroll
мероприятие. - После того, как пользователь нажмет кнопку, поскольку запрос API требует времени и не видит ответа сразу, кнопка может срабатывать постоянно.
click
мероприятие.
Я искал много информации в Интернете и обнаружил, что сценарии использования двух функций иногда противоречат друг другу, например, некоторые говорят, что нужно использовать ввод в поле поиска.debounce
Ограничьте ток, чтобы уменьшить нагрузку на сервер; некоторые говорят, что используйтеthrottle
Достаточно ограничить ток, что может быстрее вернуть результаты поиска пользователя.
На мой взгляд, нет такой вещи, как сценарий, который должен быть использован.throttle
а такжеdebounce
Один из методов лучше другого, и вам часто нужно рассматривать и выбирать в соответствии со своей ситуацией:
- Когда занятость ЦП, ГП, трафика, сервера и других ресурсов функцией реагирования на события находится в допустимом диапазоне, вы можете использовать
throttle
Ограничение потока обеспечивает лучший пользовательский опыт. - Когда функция реагирования на события занимает большое количество ресурсов, таких как ЦП, ГП, трафик и сервер, вы можете использовать
debounce
Выполните более сильное ограничение тока, тем самым снизив нагрузку.
напиши в конце
throttle-debounceИсточник меня несколько дней назад и смотрите наSindreСтиль кода написанного модуля совершенно другой.Количество строк комментариев в его коде примерно в три раза превышает количество строк кода, а параметры функции полностью закомментированы.Это должно быть хорошо, но для мне читать исходный код, мне было не легче сказать, но из-за следующей обработки необязательных параметров мне было труднее читать:
// 源码 4-2
/**
*
* @param {Number} delay
* @param {Boolean} [noTrailing]
* @param {Function} callback
* @param {Boolean} [debounceMode]
*
* @return {Function} A new, throttled, function.
*/
export default function ( delay, noTrailing, callback, debounceMode ) {
// `noTrailing` defaults to falsy.
if ( typeof noTrailing !== 'boolean' ) {
debounceMode = callback;
callback = noTrailing;
noTrailing = undefined;
}
// ...
}
В исходном коде 4-2 по комментариям видно, чтоnoTrailing
а такжеdebounceMode
необязательный параметр,delay
и обратный вызов являются обязательными параметрами, тогда это будут необязательные параметрыnoTrailing
обязательный параметрcallback
Прежде еще раз оцените код в функции: еслиnoTrailing
является функцией, значение должно использоваться какcallback
, а потомnoTrailing
установить по умолчаниюundefined
.
Я не могу не вздохнуть, что это действительно эффектная операция. Даже если она совместима с ES5, есть лучший способ написать ее. Вот лучший способ написать это, когда я лично думаю, что синтаксис ES6 доступен:
export default function (dalay, noTrailing, options = {
callback = false,
debounceMode = false,
} = {}) {
// ...
}
Обо мне: окончил Хуэк, работающий в Tencent,блог ЭлвинаДобро пожаловать в гости ^_^