Стабилизация функций и дросселирование

внешний интерфейс

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

Обычно в этом случае, как мы это решаем? В общем, стабилизация изображения и дроссель — лучшее решение.

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

Код в html файле выглядит следующим образом

<div id="content"
    style="height:150px;line-height:150px;text-align:center; color: #fff;background-color:#ccc;font-size:80px;"></div>
  <script>
    let num = 1;
    const content = document.getElementById('content');
    function count() {
      content.innerHTML = num++;
    };
    content.onmousemove = count;
  </script>

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

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

Отказаться

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

Функция защиты от сотрясений делится на версию с немедленным выполнением и версию с немедленным выполнением.

Версия без немедленного исполнения:

 function debounce(func, wait) {
  let timeout;
  return function () {
    const context = this;
    const args = [...arguments];
    if (timeout) clearTimeout(timeout);
    timeout = setTimeout(() => {
      func.apply(context, args)
    }, wait);
  }
}

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

Мы по-прежнему используем приведенный выше пример привязки события mousemove.Через приведенную выше функцию защиты от сотрясений мы можем использовать ее следующим образом.

content.onmousemove = debounce(count,1000);

Эффект следующий

Как видите, функция не выполняется до 1 секунды после запуска события, и если я запускаю событие в течение 1 секунды после запуска события, время выполнения функции пересчитывается.

В коде вышеприведенной функции защиты от сотрясений также необходимо обратить внимание на передачу this и параметров

const context = this;
const args = [...arguments];

Код функции debounce использует эти две строки кода для получения параметров this и , так что функция this, возвращаемая функцией debounce, будет указывать на то же самое и по-прежнему принимать параметр e.

Немедленно выполнить издание:

function debounce(func,wait) {
  let timeout;
  return function () {
      const context = this;
      const args = [...arguments];
      if (timeout) clearTimeout(timeout);
      const callNow = !timeout;
      timeout = setTimeout(() => {
          timeout = null;
      }, wait)
      if (callNow) func.apply(context, args)
  }
}

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

Используйте тот же метод, что и выше, эффект следующий

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

Версия с двойными мечами:

/**
 * @desc 函数防抖
 * @param func 函数
 * @param wait 延迟执行毫秒数
 * @param immediate true 表立即执行,false 表非立即执行
 */
function debounce(func, wait, immediate) {
  let timeout;
  return function () {
    const context = this;
    const args = [...arguments];
    if (timeout) clearTimeout(timeout);
    if (immediate) {
      const callNow = !timeout;
      timeout = setTimeout(() => {
        timeout = null;
      }, wait)
      if (callNow) func.apply(context, args)
    }
    else {
      timeout = setTimeout(() => {
        func.apply(context, args)
      }, wait);
    }
  }
}

дроссель

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

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

Версия временной метки:

function throttle(func, wait) {
    var previous = 0;
    return function() {
        let now = Date.now();
        let context = this;
        let args = arguments;
        if (now - previous > wait) {
            func.apply(context, args);
            previous = now;
        }
    }
}

Используйте следующим образом

content.onmousemove = throttle(count,1000);

Эффект следующий

Видно, что в процессе непрерывного срабатывания события функция будет выполняться сразу и каждую 1с.

Версия таймера:

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

    }
}

Используйте так же, как указано выше, эффект следующий

Видно, что в процессе непрерывного срабатывания события функция будет выполняться не сразу, а будет выполняться каждые 1 с.После остановки события функция будет выполняться снова.

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

Точно так же мы можем также объединить функцию регулирования версии с отметкой времени и версию с таймером, чтобы реализовать функцию регулирования версии с двойным мечом.

Версия с двойными мечами:

/**
 * @desc 函数节流
 * @param func 函数
 * @param wait 延迟执行毫秒数
 * @param type 1 表时间戳版,2 表定时器版
 */
function throttle(func, wait ,type) {
    if(type===1){
        let previous = 0;
    }else if(type===2){
        let timeout;
    }
    return function() {
        let context = this;
        let args = arguments;
        if(type===1){
            let now = Date.now();

            if (now - previous > wait) {
                func.apply(context, args);
                previous = now;
            }
        }else if(type===2){
            if (!timeout) {
                timeout = setTimeout(() => {
                    timeout = null;
                    func.apply(context, args)
                }, wait)
            }
        }

    }
}

Справочная статья:

GitHub.com/ в настоящее время имеет бриз…

GitHub.com/ в настоящее время имеет бриз…