Обновление: Спасибо за вашу поддержку.Недавно официальный сайт блога был выкинут, чтобы каждый мог его систематически читать.В будущем будет больше контента и больше оптимизации.Нажмите здесь, чтобы просмотреть
------ Далее идет текст ------
введение
В предыдущем разделе мы узнали о функции дроссельной заслонки, ее определении, принципе реализации и реализации в подчеркивании. В этом разделе мы продолжим рассказывать об антидребезговой функции, описанной в предыдущем разделе. Структура такая же. В ней будут представлены определение, принцип реализации, два вида кодов реализации и, наконец, введение в реализацию с подчеркиванием. Добро пожаловать, чтобы сделать кирпич.
Если у вас есть какие-либо идеи или мнения, вы можете оставить сообщение в области комментариев.Следующее изображение представляет собой интеллект-карту этой статьи.Пожалуйста, смотрите мою интеллект-карту в высоком разрешении и другие статьи.Github.
Определение и интерпретация
Функция отката debounce относится к функции в течение определенного периода времени, независимо от того, сколько раз запускается обратный вызов,выполняются только в последний раз. Если мы установим функцию с временем ожидания 3 секунды, если в течение этих 3 секунд будет обнаружен запрос на вызов функции, таймер будет переустановлен на 3 секунды, пока в течение новых 3 секунд не будет запроса на вызов функции, затем функция в это время будет выполняться, иначе будет выводиться и т. д. Retime.
Возьмем небольшой пример: предположим, что при посадке на автобус водитель должен дождаться, пока последний человек войдет, прежде чем закрыть дверь.Каждый раз, когда входит новый человек, водитель очищает таймер и перезапускает таймер, подождите 1 минуту. до закрытия двери. Если в течение следующей минуты в автобус не войдет ни один пассажир, водитель подумает, что все пассажиры находятся в автобусе, закроет дверь и запустит автобус.
В настоящее время «пассажиры садятся в автобус» — это задача обратного вызова, которую мы часто обрабатываем событиями и продолжаем вливать; «1 минута» — это таймер, на основании которого водитель принимает решение «закрыть дверь». новый "пассажир" садится в автобус, он будет Клиром и переназначит время; "закрыть дверь" - последняя функция, которую нужно выполнить.
Если вы все еще не можете понять, посмотрите на картинку ниже, чтобы было понятнее, и нажмитеэта страницаПосмотрите визуальное сравнение троттлинга и стабилизации.其中 Regular 是不做任何处理的情况,throttle 是函数节流之后的结果(上一小节已介绍),debounce 是函数防抖之后的结果。
Принцип и реализация
Принцип реализации заключается в использовании таймера, при первом выполнении функции устанавливается таймер, при последующем вызове функции обнаруживается, что таймер был установлен, а предыдущий таймер очищается, и новый таймер сбрасывается.Опустошенный таймер запускает выполнение функции, когда таймер истекает.
достичь 1
// 实现 1
// fn 是需要防抖处理的函数
// wait 是时间间隔
function debounce(fn, wait = 50) {
// 通过闭包缓存一个定时器 id
let timer = null
// 将 debounce 处理结果当作函数返回
// 触发事件回调时执行这个返回函数
return function(...args) {
// 如果已经设定过定时器就清空上一次的定时器
if (timer) clearTimeout(timer)
// 开始设定一个新的定时器,定时器结束后执行传入的函数 fn
timer = setTimeout(() => {
fn.apply(this, args)
}, wait)
}
}
// DEMO
// 执行 debounce 函数返回新函数
const betterFn = debounce(() => console.log('fn 防抖执行了'), 1000)
// 停止滑动 1 秒后执行函数 () => console.log('fn 防抖执行了')
document.addEventListener('scroll', betterFn)
достичь 2
Приведенная выше схема реализации может решить большинство сценариев использования, но если вы хотите реализовать fn при первом срабатывании события обратного вызова, этого недостаточно, а пока давайте перепишем функцию debounce и добавим функцию, которая выполняется сразу после первого триггера.
// 实现 2
// immediate 表示第一次是否立即执行
function debounce(fn, wait = 50, immediate) {
let timer = null
return function(...args) {
if (timer) clearTimeout(timer)
// ------ 新增部分 start ------
// immediate 为 true 表示第一次触发后执行
// timer 为空表示首次触发
if (immediate && !timer) {
fn.apply(this, args)
}
// ------ 新增部分 end ------
timer = setTimeout(() => {
fn.apply(this, args)
}, wait)
}
}
// DEMO
// 执行 debounce 函数返回新函数
const betterFn = debounce(() => console.log('fn 防抖执行了'), 1000, true)
// 第一次触发 scroll 执行一次 fn,后续只有在停止滑动 1 秒后才执行函数 fn
document.addEventListener('scroll', betterFn)
Принцип реализации относительно прост.Необходимо судить, является ли входящее немедленное истинным.Кроме того, необходимо дополнительно судить, является ли это первым разом, чтобы выполнить функцию защиты от сотрясений.Судение по-прежнему заключается в том, является ли таймер пусто, покаimmediate && !timer
Возвратите true, чтобы выполнить функцию fn, то естьfn.apply(this, args)
.
Улучшенный дроссель
Теперь рассмотрим ситуацию, если операция пользователя выполняется очень часто, следующая операция будет выполняться, не дожидаясь истечения установленного времени задержки, таймер будет часто сбрасываться и перегенерироваться, поэтому функция fn не может выполняться все время, в результате чего в отложенной операции пользователя нет ответа.
Есть идея объединить "троттлинг" и "анти-шейк" в расширенную версию функции троттлинга.Ключевым моментом является то, что "таймер может регенерироваться в течение времени ожидания, но пока время ожидания истекло, это должно быть Дать пользователю ответ». Эта комбинация идей может как раз решить проблемы, поднятые выше.
Прежде чем дать код «два в одном», давайте рассмотрим функцию газа, которая подробно описана в предыдущем разделе.
// fn 是需要执行的函数
// wait 是时间间隔
const throttle = (fn, wait = 50) => {
// 上一次执行 fn 的时间
let previous = 0
// 将 throttle 处理结果当作函数返回
return function(...args) {
// 获取当前时间,转换成时间戳,单位毫秒
let now = +new Date()
// 将当前时间和上一次执行函数的时间进行对比
// 大于等待时间就把 previous 设置为当前时间并执行函数 fn
if (now - previous > wait) {
previous = now
fn.apply(this, args)
}
}
}
В сочетании с кодами дроссельной заслонки и устранения дребезга расширенная функция дроссельной заслонки выглядит следующим образом: новая логика заключается в том, что когда разница во времени между текущим временем срабатывания и последним временем срабатывания меньше временного интервала, устанавливается новый таймер, который эквивалентно размещению кода устранения дребезга во временном интервале, меньшем временного интервала.
// fn 是需要节流处理的函数
// wait 是时间间隔
function throttle(fn, wait) {
// previous 是上一次执行 fn 的时间
// timer 是定时器
let previous = 0, timer = null
// 将 throttle 处理结果当作函数返回
return function (...args) {
// 获取当前时间,转换成时间戳,单位毫秒
let now = +new Date()
// ------ 新增部分 start ------
// 判断上次触发的时间和本次触发的时间差是否小于时间间隔
if (now - previous < wait) {
// 如果小于,则为本次触发操作设立一个新的定时器
// 定时器时间结束后执行函数 fn
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
previous = now
fn.apply(this, args)
}, wait)
// ------ 新增部分 end ------
} else {
// 第一次执行
// 或者时间间隔超出了设定的时间间隔,执行函数 fn
previous = now
fn.apply(this, args)
}
}
}
// DEMO
// 执行 throttle 函数返回新函数
const betterFn = throttle(() => console.log('fn 节流执行了'), 1000)
// 第一次触发 scroll 执行一次 fn,每隔 1 秒后执行一次函数 fn,停止滑动 1 秒后再执行函数 fn
document.addEventListener('scroll', betterFn)
Глядя на полный код, вы обнаружите, что эта идея очень похожа на идею реализации дроссельной заслонки в подчеркивании, представленную в предыдущей статье.
подчеркивание анализа исходного кода
После прочтения базовой версии приведенного выше кода я чувствую себя относительно расслабленным. Теперь давайте узнаем, как подчеркивание реализует функцию устранения дребезга, изучим несколько отличных идей и напрямую добавим код и комментарии. Этот анализ исходного кода зависит отunderscore 1.9.1реализация версии.
// 此处的三个参数上文都有解释
_.debounce = function(func, wait, immediate) {
// timeout 表示定时器
// result 表示 func 执行返回值
var timeout, result;
// 定时器计时结束后
// 1、清空计时器,使之不影响下次连续事件的触发
// 2、触发执行 func
var later = function(context, args) {
timeout = null;
// if (args) 判断是为了过滤立即触发的
// 关联在于 _.delay 和 restArguments
if (args) result = func.apply(context, args);
};
// 将 debounce 处理结果当作函数返回
var debounced = restArguments(function(args) {
if (timeout) clearTimeout(timeout);
if (immediate) {
// 第一次触发后会设置 timeout,
// 根据 timeout 是否为空可以判断是否是首次触发
var callNow = !timeout;
timeout = setTimeout(later, wait);
if (callNow) result = func.apply(this, args);
} else {
// 设置定时器
timeout = _.delay(later, wait, this, args);
}
return result;
});
// 新增 手动取消
debounced.cancel = function() {
clearTimeout(timeout);
timeout = null;
};
return debounced;
};
// 根据给定的毫秒 wait 延迟执行函数 func
_.delay = restArguments(function(func, wait, args) {
return setTimeout(function() {
return func.apply(null, args);
}, wait);
});
По сравнению с базовой версией, описанной выше, подчеркивание имеет следующие функции.
- 1. После завершения выполнения функции func вернуть значение результата
- 2. По истечении времени таймера очистите тайм-аут, чтобы он не влиял на срабатывание следующего непрерывного события.
- 3. Добавлена функция ручной отмены отмены.
- 4. После того, как немедленное значение равно true, оно будет выполняться только при первом запуске и не будет выполняться после завершения частого обратного вызова триггера.
резюме
-
Дросселирование функций и защита от сотрясения являются приложениями «замыканий» и «функций более высокого порядка».
-
Функция дросселирования газа относится к функции, которая выполняется один раз в течение определенного интервала времени (например, 3 секунды), в течение которого 3 секундыИгнорировать последующие запросы вызова функции
- Под дросселированием можно понимать закручивание крана для выпуска воды при выращивании золотых рыбок, одна капля на 3 секунды
- «Вода в трубе» — это задача обратного вызова, которую мы часто обрабатываем событиями и продолжаем вливать, она должна принять расположение «крана».
- «Кран» — это дроссельный клапан, который регулирует расход воды и фильтрует недопустимые задачи обратного вызова.
- "Drip" - выполнять функцию время от времени.
- «3 секунды» - это интервал времени, который является основанием для «крана» для определения «капельки».
- Применение: после отслеживания события прокрутки и добавления функции дроссельной заслонки выполняйте ее каждый фиксированный период времени.
- План реализации 1: Используйте метку времени, чтобы определить, наступило ли время выполнения, запишите метку времени последнего выполнения, а затем выполните обратный вызов после каждого триггера, чтобы определить, достиг ли интервал между текущим временем и последним временем выполнения время разница (Xms), если да, выполнить и обновить метку времени последнего выполнения и т. д.
- Реализация 2: Используйте таймер, например, когда событие прокрутки только что срабатывает, напечатайтеhello world, затем установите таймер на 1000 мс, а затем запускайте обратный вызов каждый раз, когда запускается событие прокрутки.Если таймер уже есть, обратный вызов не будет выполнять метод до тех пор, пока таймер не сработает и обработчик не будет очищен, а затем сбросьте таймер
- Под дросселированием можно понимать закручивание крана для выпуска воды при выращивании золотых рыбок, одна капля на 3 секунды
-
Функция debounce debounce относится к функции в течение определенного периода времени, независимо от того, сколько раз запускается обратный вызов.выполняются только в последний раз
-
Anti-shake можно понимать как водитель ждет, пока последний человек войдет, а затем закрывает дверь.Каждый раз, когда входит новый человек, водитель сбрасывает таймер и перезапускает таймер.
- «Пассажиры садятся в автобус» — это задача обратного вызова, которую мы часто обрабатываем событиями и продолжаем вливать.
- «1 минута» — это таймер, на основании которого водитель принимает решение «закрыть дверь».Если в автобус садится новый «пассажир», он обнуляется и таймер запускается заново.
- «Закрыть дверь» — последняя функция, которую необходимо выполнить
-
Применение: после добавления функции защиты от сотрясения к событию обратного вызова ввода, она будет запускаться только один раз после остановки ввода.
-
План реализации: использовать таймер, установить таймер при первом выполнении функции, а затем очистить предыдущий таймер при его вызове, когда будет обнаружено, что таймер был установлен, и сбросить новый таймер. , когда таймер истечет, вызовите функцию для выполнения
-
Ссылаться на
Принцип и практика оптимизации производительности интерфейса
Челнок статей
- [Дополнительно 6-3 период] Объясните простыми словами функцию дроссельной заслонки.
- [Дополнительно 6-2] Углубленное каррирование приложений функций высшего порядка
- [Дополнительно 6-1] Анализ функций высшего порядка в JavaScript
- [Расширенная фаза 5-3] Углубленное изучение проблемы яйца функции и объекта
- [Расширенная фаза 5-2] Цепочка графических прототипов и ее преимущества и недостатки наследования
- [Расширенная фаза 5-1] Повторное распознавание конструкторов, прототипов и цепочек прототипов