Пишем вместе throttle и debounce | Уроки JavaScript

Sdílet
Vložit
  • čas přidán 25. 07. 2024
  • Разберём зачем нужны функции throttle и debounce, вместе реализуем и разберём различия.
    🍀 Поддержать канал: www.donationalerts.com/r/webe...
    ☕️ Купить кофе: buy.stripe.com/5kA7sL9574SG7x...
    🎨 Купить набор кистей Procreate: webelart.com/illustration.
    ✍️ Мой telegram channel: t.me/webelart
    🏰 Английский CZcams: @webelart_en
    💁🏼‍♀️ Инстаграм: / webelart
    🦄 LinkedIn: / webelart
    ❤️ Пример кода из урока: / shpargalka-51868113 .
    00:00 введение.
    00:29 debounce
    11:16 throttle
    На канале я рассматриваю различные темы веб-разработки, на текущий момент: веб-основы, веб-анимации, веб-дизайн.

Komentáře • 52

  • @Polina-rx2kj
    @Polina-rx2kj Před rokem +4

    У тебя очень классные уроки! Cпасибо за то, что ты делаешь 💞💞

  • @99k27
    @99k27 Před 11 měsíci

    от души душевно в душу, выручила!

  • @user-qj2hh8rr3i
    @user-qj2hh8rr3i Před 2 lety

    Супер! Спасибо!

  • @user-er3le7uo6v
    @user-er3le7uo6v Před 3 lety +3

    Было очень интересно!♥️ Спасибо большое за ваш труд! Больше видео по JavaScript♥️

    • @webelart
      @webelart  Před 3 lety

      Спасибо за просмотр! 😍❤️

  • @arsenmanasuev4934
    @arsenmanasuev4934 Před 3 lety

    Спасибо ) не знал что это так называется ) решал это несколько по другому

  • @egoist2956
    @egoist2956 Před 2 lety +1

    Лайк!

  • @quite10
    @quite10 Před 3 lety +3

    Всем рекомендую❤️ Вы мастер объяснений🥰

    • @webelart
      @webelart  Před 3 lety +1

      Ого, спасибо большое! ❤️

  • @Vllad_Ko
    @Vllad_Ko Před 28 dny

    #webelart throttle попробуйте вызвать в строгом режиме и нет,
    интересно
    что-то измениться?
    Подсказка
    будет разный результат.
    Может лучше на 40 строке сделать saveThis || saveArgs
    А так, материал -- супер!

  • @alexalex4601
    @alexalex4601 Před rokem

    короче, неплохо. Можно даже сказать, хорошо!

  • @user-qx6gp9ci5d
    @user-qx6gp9ci5d Před 2 lety

    круто

  • @theoty-js
    @theoty-js Před rokem

    Преподаватель от бога:)

  • @Ramosok
    @Ramosok Před 2 lety

    Отличный контент, очень целевой, коротко и по делу.

  • @romanryaboshtan9270
    @romanryaboshtan9270 Před 3 lety +2

    Хорошее видео, был один момент, которого я не знал

  • @user-qj2hh8rr3i
    @user-qj2hh8rr3i Před 2 lety +1

    Получается debounce() обертка генерит функции, которые юзают один и тот же timer (из замыкания). Мне для каждого случая (когда нужны разные timer) создавать свою debounce() ? Хотелось бы еще разобрать метод, наподобие createDebounce(). Или я вообще не в том направлении думаю?

    • @webelart
      @webelart  Před 2 lety +1

      Интересный вопрос, задумалась над этим. Давайте посмотрим. Приведу примеры, которые я часто использую для debounce, у меня это со всякими resize, change events:
      input.addEventListener('change', debounce(updateValue));
      window.addEventListener('resize', debounce(updateValue));
      Т.е. для каждого случая в этом примере по факту своя обёртка. Здесь наверно встаёт вопрос, что если мы хотим в одну функцию вынести deboundedUpdate = debounce(updateValue) и одновременно использовать эту обёрнутую функцию. То здесь могут быть затирки timer, их не очистка и отрабатывание setTimeout. В целом по ощущениям к каким-то глобальным ошибкам не приведёт, но тем не менее не круто.
      Про createDebounce(), не поняла, что имеете ввиду.

    • @user-un4jd3gh3g
      @user-un4jd3gh3g Před rokem

      Функция в глобальном скоупе. Надо делать объект кмк

  • @ondrui
    @ondrui Před 8 měsíci

    Спасибо за урок! Интересная тема и практичная.
    Вот мне кажется в debounce в setTimeout можно коллбэк передавать без apply и this. Только саму функцию и аргументы. Может я что-то упустил?!

    • @webelart
      @webelart  Před 5 měsíci

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

  • @soldat675
    @soldat675 Před rokem

    объясните пожалуйста, почему debounce в этом примере не срабатывает:
    textarea.addEventListener('input', (e) => {
    debounce( () => { console.log('1'); }, 2000);
    }

    • @webelart
      @webelart  Před rokem

      Debounce возвращает новую функцию, т.е. вы ничего здесь не вызываете. Вам нужно целиком колбек обернуть, тогда при срабатывание события 'input' на textarea функция будет автоматически вызываться.
      const debouncedCallback = debounce((e) => {....}, 2000)
      textarea.addEventListener('input', debouncedCallback)
      Что-то такое должно получиться.

    • @soldat675
      @soldat675 Před rokem

      @@webelart спасибо большое

  • @romanryaboshtan9270
    @romanryaboshtan9270 Před 2 lety

    Вот это

    • @webelart
      @webelart  Před 2 lety +1

      CZcams кажется опять трёт комментарии. Вот эту ссылку скидывали github.com/lukasoppermann/html5sortable/blob/master/src/throttle.ts
      Прикольная реализация, мне понравилась. Решение выглядит действительно проще, но здесь есть неучтённый момент. Например, мы делаем эту обёртку и у нас вызывается кучу событий скролла предположим (или других вызовов) и данная функция не даёт гарантии, что последнее значение скролла будет вызвано. Для меня как раз в решении, хотелось эту штуку учесть. Т.е. если последний вызов попал на время, которое ещё не вошло в условие, это значит, что мы потеряли самый последний вызов, а терять его не хочется. Поэтому решение в примере из видео более такое может громоздкое, там сохраняются переменные и потом в таймере вызываются, т.е. всегда последний вызов будет вызван с самыми последними значениями.

    • @romanryaboshtan9270
      @romanryaboshtan9270 Před 2 lety

      @@webelart Я проверял, здесь вызывается последний запрос, в том то и дело. Оно работает так же само, просто меньше кода

    • @webelart
      @webelart  Před 2 lety

      ​@@romanryaboshtan9270 Здесь нужно смотреть разные кейсы. Например, вот этот кейс не работает:
      const f = throttle(console.log, 500);
      f(1);
      f(2);
      setTimeout(() => f(3), 100);
      setTimeout(() => f(4), 500);
      setTimeout(() => f(5), 900);
      Вызывается только 1 и 4.

    • @romanryaboshtan9270
      @romanryaboshtan9270 Před 2 lety

      @@webelart да, вы правы, я там поменял условие >= delay + 2 - теперь и этот кейс, который вы указали, работает, вызывается 1, 4 и 5. Я ещё раз проверил, да, здесь есть небольшой баг, ваш вариант лучше, согласен

    • @webelart
      @webelart  Před 2 lety

      @@romanryaboshtan9270 Вы сейчас пошутили? о_О Вы же понимаете, что кейсов может быть куча и я к своему примеру тоже +2 могу добавить. Что решения в программировании должны быть универсальными. А код, который вы предоставили не будет работать в задаче которую я описала, я имею ввиду работать в 100% различных кейсов, а не в 3% по случайности. И в примере даже нет написанных строк, которые заставят его работать так, там одно условие и если оно не сработает вызов будет потерян. В моём примере есть setTimeout, который словит последний вызов, обязательно словит и с нужными переменными.

  • @flogger2367
    @flogger2367 Před rokem

    В функции дебаунс я бы все таки сделал, чтобы первый вызов всегда вызывался, добавив булевый флаг... А дальше уже регулировал по таймингу... Но возможно это уже от типа задачи к
    Как всегда уроки хорошие, понятно и приятно смотреть ..ум и красота страшная сила 💪 :)

  • @imgod113
    @imgod113 Před 2 lety

    Не совсем понимаю зачем в debounce делаем callback.apply(this) если стрелочная функция и так передает контекст ?

  • @max-ek5uu
    @max-ek5uu Před 2 lety +2

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

  • @lvivduncan
    @lvivduncan Před 3 lety

    спасибо, Елена!)
    подскажите -- как Вы решаете "проблему ресайза", когда при изменении размера дисплея нужно выполнить функцию (только раз) и вернуть все обратно при изменении в другую строну? debounce замедлит, но данное решение не єлегантное. использую flag, но может есть решение лучше

    • @webelart
      @webelart  Před 3 lety +1

      Прямо, чтобы один раз сработало, из решений здесь по факту нужен debounce и какая-нибудь переменная flag, типа только один раз сработай. Устанавливаете false, вначале и true, как только прошло событие.
      Но здесь ещё интересно, что за поведение более подробно, возможно debounce и не нужен. Просто по факту, вы же можете ещё и ресайзить потом окно, например чутка сресайзили и ещё раз потом чутка. Т.е. вы пишите ресайз и хотите чтобы вот при каждом ресайзе, максимум один раз сработала и только в самом конце, т.к. пользователь может реально вертеть этим окном полминуты, странная конечно ситуация, но тем не менее. Если так, то debounce с временем в секунды 2 и как только пользователь ничё не делает 2 секунды, то всё работаем. :))))

    • @lvivduncan
      @lvivduncan Před 3 lety

      @@webelart спасибо, так и делаю)

  • @romanryaboshtan9270
    @romanryaboshtan9270 Před 2 lety

    Есть реализация throttle другая

  • @andrewananenko797
    @andrewananenko797 Před 2 lety

    Почему у вас вместо 1,4,5 вызывается 1,3,5 ?

    • @webelart
      @webelart  Před 2 lety

      Напишите, какая минута.

    • @TheDaZorg
      @TheDaZorg Před rokem

      @@webelart 21:06
      3 вывелась, как последнее значение (по аналогии с последней 5), вопрос скорее в том - почему нет 4, т.е. вывод не 1 3 4 5?

    • @webelart
      @webelart  Před rokem +1

      @@TheDaZorg Слушайте правда странно, по логике должно 1,4,5 Но когда писала код, почему-то это не смутило. Вы пробовали набирать у себя в редакторе? Также выводится? Попробую найти время на выходных вновь набрать и проверить подробнее.

    • @TheDaZorg
      @TheDaZorg Před rokem

      @@webelart С такими параметрами должно быть нагляднее:
      const f = throttle(console.log, 400);
      f(1);
      f(2);
      setTimeout(() => f(3), 100);
      setTimeout(() => f(4), 500);
      setTimeout(() => f(5), 900);
      Вроде должно быть 1 3 4 5:
      1 -выводится, т.к. это первое значение
      2 - пропускаем, все понятно
      3 - выводится, т.к. в f замкнуто значение ожидания в 400 и по окончании этого времени последнее значение будет 3 (такое поведение стало после рефакторинга для вывода последнего значения)
      4 - по аналогии с 3
      5 - по аналогии с 3
      Если в f замкнуть время 500мс, то будет пограничный случай, т.к. время для 3 будет совпадать (но это не точно :D), у меня лично выводится тоже самое, что и в примере выше - 1 3 4 5, но я немного отрефакторил функцию:
      function throttle(cb, delay) {
      let isWaiting = false;
      let savedArgs;
      return (...args) => {
      if (isWaiting) {
      savedArgs = args;
      return;
      }
      cb(...args);
      isWaiting = true;
      setTimeout(() => {
      isWaiting = false;
      if (savedArgs) {
      cb(...savedArgs);
      savedArgs = null;
      }
      }, delay);
      };
      }

  • @user-er3le7uo6v
    @user-er3le7uo6v Před 3 lety

    Сложно было изучать JavaScript?)

    • @webelart
      @webelart  Před 3 lety +4

      🤔 Сложно так даже вспомнить, постепенно всё шло, усложнения, более сложные конструкции и их понимание. Помню самое сложное было начать вообще программировать, первый курс универа и c++, не сразу далось понимание механики.
      В программировании очень важна практика, как только появились первые теоретические знания и сразу пробовать. Хотя чаще с JavaScript было наоборот, появилась задача и нужно понять как её сделать, да побыстрее. 😄

    • @user-er3le7uo6v
      @user-er3le7uo6v Před 3 lety

      @@webelart у меня какие-то темы легко идут, а какие-то нет, сейчас засела на Switch Case, посмотрела видео и казалось всё очень просто, нахожу задания и всё....😅💔

    • @webelart
      @webelart  Před 3 lety

      @@user-er3le7uo6v 😊 Это нормально, у меня тоже таких тем полно, когда не сразу дошло.

  • @romanryaboshtan9270
    @romanryaboshtan9270 Před 2 lety

    Проще с date.now

    • @webelart
      @webelart  Před 2 lety +1

      Это когда в setTimout кладётся разница текущего и прошлого времени и сравнивается с delay?

  • @vadavur
    @vadavur Před 2 lety

    Спасибо за видео!
    А как правильно делать throttle, чтобы в итоге выполнялись все вызовы функций, просто не сразу, а с дилеем?
    Я сделал такой вариант с использованием очереди, но, может, есть какой-то канонизированный вариант?
    (Может, это вообще уже не throttle называется)
    function throttle(callback, delay) {
    let queueHead = {next: null, cb: null};
    let queueTail = queueHead;
    let isAwaiting = false;
    return function(...args) {
    if (isAwaiting) {
    queueTail.cb = callback.bind(this, ...args);
    queueTail.next = {next: null, cb: null};
    queueTail = queueTail.next;
    return;
    }
    callback(...args);
    isThrottling = true;
    moveQueue();
    function moveQueue(){
    setTimeout(() => {
    if (!queueHead.cb) {
    isAwaiting = false;
    } else {
    queueHead.cb();
    queueHead = queueHead.next;
    setTimeout(() => moveQueue(), delay);
    }
    }, delay);
    };
    }
    }
    let cat = {
    meowLevel: '',
    sayMeow: function(speechTone = 'calmly') {
    console.log(`Meow!${this.meowLevel} - cat said ${speechTone}`);
    this.meowLevel += '!';
    },
    }
    let begForFood = throttle(cat.sayMeow.bind(cat), 500);
    begForFood();
    begForFood();
    begForFood('impatiently');
    begForFood('angrily');
    begForFood('furiously');