Отказ в Javascript

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

Версия 1:

@index.html

<input type = "text" oninput = "betterFunction()">

@script.js

function getData() {
  console.info('Data Fetched')
}

function debounce(callback, delay) {
  let timer
  return function() {
    clearTimeout(timer)
    timer = setTimeout(() => {
      callback();
    }, delay)
  }
}

const betterFunction = debounce(getData, 1000)

Версия 2:

@index.html

<input type = "text" oninput = "debounce()">

@script.js

let timer

function debounce() {
  clearTimeout(timer)
  timer = setTimeout(() => {
    console.info('Data Fetched');
  }, 1000)
}

В чем разница между этими двумя способами устранения дребезга, если они оба дают одинаковый результат? PS: Я удивлен, что я никогда не видел, чтобы кто-то использовал «версию 2», конечно, что-то не так. Может ли кто-нибудь объяснить различия, пожалуйста?

Один параметризован (т. е. вы можете указать задержку и обратный вызов при вызове), а другой — нет. Но, как вы уже признали, результат тот же.

Marc 11.04.2023 19:44

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

Barmar 11.04.2023 19:45

Это можно использовать, верно, для нескольких входов? <input type = "text" oninput = "debounce(()=>{//code}, 1000)"> функция таймера debounce(cb, delay) { clearTimeout(timer) timer = setTimeout(() => { cb (); }, задерживать) }

Voodoo Child 12.04.2023 12:32
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
3
146
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Версия 1 лучше, потому что она:

  • инкапсулирует timer (идентификатор тайм-аута) в пределах времени жизни вызова функции
  • устраняет неприятные глобальные переменные, которые могут быть случайно изменены вне или внутри другой функции
  • самое главное, это многоразовое использование

Еще лучшее устранение дребезга

У Джоша В. Комо есть информативная статья о борьбе с дребезгом.

Вот его (модифицированная) минимальная версия:

const debounce = (callback, wait) => {
  let timeoutId = null;
  return (...args) => {
    window.clearTimeout(timeoutId);
    timeoutId = window.setTimeout(() => {
      callback(...args);
    }, wait);
  };
}

Примечание: я заменил callback.apply(null, args) более лаконичным callback(...args)

Применение

const handleMouseMove = debounce((mouseEvent) => {
  // Do stuff with the event!
}, 250);

document.addEventListener('mousemove', handleMouseMove);    // Add listener
document.removeEventListener('mousemove', handleMouseMove); // Remove listener

Фрагмент

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

const debounce = (callback, wait) => {
  let timeoutId = null;
  return (...args) => {
    window.clearTimeout(timeoutId);
    timeoutId = window.setTimeout(() => {
      callback(...args);
    }, wait);
  };
}

const createPoint = (x, y, color) => {
  const point = Object.assign(document.createElement('div'), { className: 'point' });
  Object.assign(point.style, { top: `${y - 2}px`, left: `${x - 2}px`, background: color });
  document.body.append(point);
  return point;
};

// Log mouse coordinates when user stops moving mouse after 250ms
const handleMouseMove = debounce(({ clientX: x, clientY: y }) => {
  console.info(`Creating MOVE point at: (${x}, ${y})`);
  const point = createPoint(x, y, 'white');
  // Auto-remove after 1 second
  setTimeout(() => {
    console.info(`Removing MOVE point at: (${x}, ${y})`);
    point.remove();
  }, 2000);
}, 250);

// Log mouse coordinates when user stops clicking 250ms
const handleClick = debounce(({ clientX: x, clientY: y }) => {
  console.info(`Creating CLICK point at: (${x}, ${y})`);
  const point = createPoint(x, y, 'red');
  // Auto-remove after 1 second
  setTimeout(() => {
    console.info(`Removing CLICK point at: (${x}, ${y})`);
    point.remove();
  }, 2000);
}, 250);

document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('click', handleClick);
.as-console-wrapper { max-height: 5em !important; }
html, body { width: 100%; height: 100%; margin: 0; padding: 0; }
body { background: #222; position: relative; }
.point { position: absolute; width: 4px; height: 4px; border-radius: 50%; background: #FFF; }

Спасибо за это замечательное объяснение. Я прошел по ссылке, которую вы дали, это было действительно полезно. Однако теперь у меня есть только одно сомнение: внешняя функция, которая инкапсулирует переменную таймера ...., запускается только один раз в начале, после чего вызывается только возвращаемая функция. Я прав?

Voodoo Child 12.04.2023 13:20

@VoodooChild, когда вы оборачиваете функцию в debounce, вы, по сути, привязываете свою собственную локальную timeoutId к этой функции. Возвращаемая функция — это фактическая функция, которую вы передаете обработчику событий. Всякий раз, когда срабатывает обратный вызов, он имеет ссылку на эту границу timeoutId на время существования внешней функции. Функция, которая возвращает функцию при вызове, является функцией. debounce — это, по сути, фабрика, которая возвращает суперфункцию, имеющую собственную ограниченную область видимости. Это все еще функция в конце дня.

Mr. Polywhirl 12.04.2023 14:23

Спасибо еще раз, я благодарен за ваши усилия.

Voodoo Child 12.04.2023 15:45
Ответ принят как подходящий

Функция отката — это шаблон программирования javascript для задержки выполнения функции, ваша версия 1 является общепринятым шаблоном для реализации функции отката, потому что она лучше, чем версия 2, по причинам, перечисленным MR. Поливихрь.

Шаблон на самом деле использует функцию javascript, называемую closure, которая позволяет внутренней функции (функции, возвращаемой debounce) получать доступ к своей внешней области видимости (в частности, в данном случае к объявленной переменной timer).

Вы можете подробно прочитать о замыканиях здесь , чтобы лучше понять, почему версия 1 является предпочтительной версией, но это объяснение/пример замыканий может быть легче понять поначалу.

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

Voodoo Child 12.04.2023 10:32

Спасибо, что предоставили мне эти ссылки. Пример со встречной дилеммой в значительной степени прояснил большую часть моих недоразумений.

Voodoo Child 12.04.2023 13:22

Другие вопросы по теме