Gavr_Gavr
@Gavr_Gavr

Как правильно создать декоратор для функции?

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

Использую такой код:

function f(x) {
      alert(x);
   }

   function calls(func, ms) {
      let call = true
      return function (x) {
         console.log("UP: " + call + " " + x)
         if (!call) {
            setTimeout(() => { call = true }, ms);
            return false
         } else {
            console.log("BEFORE: " + call + " " + x)
            call = false;
            console.log("AFTER: " + call + " " + x)
            return func.apply(this, arguments);
         }
      }
   }


   // создаём обёртку
   f = calls(f, 1000);

   f(1);// выполняется
   f(2);// не выполняется
   setTimeout(() => f(3), 100);// не выполняется
   setTimeout(() => f(4), 1100); // выполняется
   setTimeout(() => f(5), 1500); // должен быть проигнорирован (прошло только 400 мс от последнего вызова), но он выполняется!


5тый вызов функции f выполняется (хотя должен быть проигнорирован). Консоль показывает что после 4го вызова переменная call==false и тут же на 5 вызове она меняется на true. И самое странное, если я дебажу код и ставлю брейкпоинт на строке console.log("UP: " + call + " " + x). То переменная call на 5то вызове получает false (как и задумано) и вызов не происходит.

Кто то может мне объяснить что я делаю не так и почему call==false превращается в call==true на 5том вызове?

Вот ссылка на фидл
  • Вопрос задан
  • 78 просмотров
Решения вопроса 1
alexey-m-ukolov
@alexey-m-ukolov Куратор тега JavaScript
Всё довольно просто - вы не в той ветке логики сбрасываете флаг-блокировщик, вот он и сбрасывается через секунду после третьего вызова (как раз между четвёртым и пятым).
Вот такой вариант работает:
function calls(func, ms) {
  let call = true;
  return function (x) {
     if (call) {
        call = false;

        setTimeout(() => { call = true }, ms);

        return func.apply(this, arguments);
     }
  }
}
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
delphinpro
@delphinpro Куратор тега JavaScript
frontend developer
Ответ написан
Комментировать
@rifat2125
function Throttle(fn, ms) {
  let timer = null;

  return function throttling(...args) {
    if (timer) return;

    timer = setTimeout(() => {
      fn(...args);
      clearTimeout(timer);
      timer = null;
    }, ms);
  }
}

 f = Throttle(f, 1000);

 f(1);// выполняется
 f(2);// не выполняется
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы