Разговор об устранении дребезга и дросселировании функций в JavaScript

JavaScript

Почему анти-встряска и дроссель

Иногда некоторые события часто запускаются во время разработки проекта, напримерresize,scroll,keyup,keydownи т. д., или функция поиска в реальном времени, такая как поле ввода, мы знаем, что если обработчик событий вызывается неограниченно, это значительно увеличит рабочую нагрузку браузера, что может привести к зависанию страницы и повлиять на работу; частые вызовы фонового интерфейса не только повлияют на работу клиента, но и значительно увеличат нагрузку на сервер. Не было бы неплохо добавить ограничение на эти функции вызова, чтобы уменьшить частоту вызова?

Обычно есть два решения этой проблемы:Отказаться Дроссель

Отказаться

Мое определение функции debounce:Когда функция вызывается непрерывно, функция не выполняется и выполняется только один раз, когда все вызовы остановлены более чем на определенный период времени.

Часто приводимый пример:

При входе в лифт все входят друг за другом, и дверь лифта не закрывается, лифт закрывается только тогда, когда в течение некоторого времени никто не подходит.

Говорить дешево, давайте покажем код напрямую.

Сначала выполните основные приготовления (из соображений экономии места часть HTML опущена):

let container = document.getElementById('container');

// 事件处理函数
function handle(e) {
    console.log(Math.random()); 
}

// 添加滚动事件
container.addEventListener('scroll', handle);

Мы обнаружили, что при каждой прокрутке консоль выводит строку случайных чисел.

Базовая стабилизация изображения

Теперь мы напишем самую простую обработку для защиты от сотрясений:

function debounce(func, wait) {
    var timeout;//标记
    return function() {
      clearTimeout(timeout);
      timeout = setTimeout(func, wait);
    }
}

Событие также переписывается следующим образом:

container.addEventListener('scroll', debounce(handle, 1000));

Попробуйте сейчас, и мы увидим, что консоль печатает строку случайных чисел только тогда, когда мы останавливаем прокрутку на 1 секунду.

Стандартная стабилизация изображения

Вышеупомянутая базовая версия будет иметь две проблемы, см. следующий код:

// 处理函数
function handle(e) {
    console.log(this); //输出Window对象
    console.log(e); //undefined
}

Правильно, когда мы не используем антивибрационную обработку,handle()функциональныйthisУказывает на контейнер, который вызывает эту функцию, и после использования антивибрационной обработки во внешнем слое точкой этого станет Window. Во-вторых, нам также нужно получить объект событияevent.

Итак, нам нужно переписать функцию защиты от сотрясений следующим образом:


function debounce(fn, wait) {
  let timeout;
  return function() {
    let that = this;
    let arg = arguments;
    clearTimeout(timeout);
    timeout = setTimeout(function(){
      fn.apply(that,arg)//使用apply改变this指向
    }, wait);
  }
}

Конечно, если вы используете стрелочные функции, вы можете опустить внешнее объявление.

Защита от сотрясения при первом срабатывании

Вышеупомянутые случаи выполняются только после прекращения непрерывного срабатывания.Если мы хотим, чтобы событие выполнялось в первый раз, последующее непрерывное срабатывание не будет выполняться, и оно может быть запущено снова, пока оно не прекратит срабатывание в течение определенного периода времени ( например предотвращение частых нажатий) , как с этим бороться?

Затем вы можете использовать тот же принцип с небольшой модификацией:

function debounce(fn, wait) {
    let timeout;
    return function(){
      let arg = arguments;
      let that = this;
      clearTimeout(timeout);
      !timeout && fn.apply(that,arg)
        timeout = setTimeout(function(){
          timeout = null;
        }, wait);
    }
}

Дроссель

Как подсказывает название,Дросселирование предназначено для экономии трафика и разбавления постоянно инициируемых событий до заданного рейтинга.Например, функция выполняется каждую 1 секунду, независимо от того, сколько раз событие срабатывало за этот период.

Это немного похоже на автобус: сколько бы людей ни ждало на остановке, автобус придет только вовремя, и ни одного автобуса не будет.

Стандартное регулирование

function throttle(fn, wait) {
  let timeout; 
  return function () {
    if (!timeout) { 
      timeout = setTimeout(() => {
        timeout = null;
        fn.apply(this, arguments)
      }, wait)
    }
  }
}

Использование событий прокрутки для описания дросселирования на самом деле является очень типичным сценарием, например, события прокрутки нужно использовать, чтобы определить, следует ли загружать больше.

дросселирование первого триггера

Как и в случае с функцией защиты от сотрясений, описанная выше ситуация заключается в том, чтобы сначала подождать, а затем запустить.Если мы хотим, чтобы событие сначала запускалось, а затем ждало, как с этим справиться? Большинство статей в Интернете советуют использовать временные метки для достижения этой цели, но на самом деле этого можно добиться с помощью небольшой модификации, например, защиты от сотрясений.

function throttle(fn, wait) {
  let timeout; 
  return function () {
    if (!timeout) { 
      fn.apply(this, arguments)
      timeout = setTimeout(() => {
        timeout = null;
      }, wait)
    }
  }
}

Таким образом, мы обнаружим, что при первом запуске функции она вступит в силу немедленно.

Суммировать

Что касается защиты от сотрясений и дросселирования, библиотеки инструментов, такие как lodash и underscore, имеют полные реализации, которые можно использовать напрямую, нет необходимости создавать колеса. Цель этой статьи состоит только в том, чтобы показать ее основные идеи и идеи реализации. Что еще более важно, зная природу анти-тряски и дросселирования, вы будете знать, когда использовать анти-тряску или дросселирование, и когда запускать сначала или позже. Независимо от того, как меняются потребности, его можно использовать гибко.