Кэширование отклоненных функций в Javascript

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

Я объясню свой мыслительный процесс, шаг за шагом:

Вот оригинальная дебаунс-функция

hideElementWhenIdle = _.debounce(($el) => {
  if($el.is(":hover"))
    hideElementWhenIdle($el);
  else
    $el.removeClass("visible");
}, 5000);

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

hideElementWhenIdle( $("selector-1") );
hideElementWhenIdle( $("selector-2") );

они в основном осуждали друг друга. Я хотел, чтобы у каждого элемента были уникальные функции.

Грязный раствор

Конечно, я мог бы сделать что-то вроде этого:

hideElementWhenIdle = function($el) {
  let fn = _.debounce(($el) => {
    // ... same as above
  }, 5000);
  
  return fn;
}

hideSelector1WhenIdle = hideElementWhenIdle( $("selector-1") );
hideSelector2WhenIdle = hideElementWhenIdle( $("selector-2") );

Теперь у меня будет две независимые функции, которые я могу вызывать. Однако это явно грязно и не масштабируется (хотя, честно говоря, у меня есть только два элемента, которые мне нужно применить для работы в любом случае).

Неудачная попытка

Я думал, что смогу wrap и memoize выполнить свою функцию, чтобы добиться того, что я хотел сделать, но после нескольких попыток я не могу понять, что происходит (или правильное ли это решение). Вот моя последняя попытка:

var hideElementWhenIdle = _.wrap(
  _.memoize( 
    function($el) {
      var fn = _.debounce(() => {
        // ... same as above
      }
    ),
  function(func, $el) {
    return func($el);
  }
);

Я предполагаю, что моя проблема здесь в том, что _.debounce всегда возвращает одно и то же значение, поэтому я всегда кэширую одно и то же значение независимо от $el.


person Sunyatasattva    schedule 23.07.2017    source источник
comment
грязное решение, на мой взгляд, довольно чистое и надежное...   -  person Jonas Wilms    schedule 23.07.2017


Ответы (1)


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

function debounce(func,time){
   var debouncing=new Map();
   return function(el){
        if(!debouncing.get(el)){
            debouncing.set(el,setTimeout(_=>debouncing.set(el,null),time));
            return func(el);
        }
    };
}

вариант использования:

var func=debounce(function(el){
   $el=$(el);
   if($el.is(":hover"))
      hideElementWhenIdle($el);
   else
     $el.removeClass("visible");
 }, 5000);

func("#sth");
func("#sth");//debounced
func("#sthelse");//not debounced

Примечание: это не будет работать с передачей объектов jquery, поскольку они уникальны. Узлы DOM будут работать.

http://jsbin.com/bujocoravu/1/edit?js

person Jonas Wilms    schedule 23.07.2017
comment
Мм… спасибо за ответ. Проблема с грязным решением заключается в том, что оно полностью не масштабируется, поскольку я продолжаю добавлять элементы. Я не пробовал вашу функцию debounce, но похоже, что она может помочь. Хотя я бы не хотел снова писать весь debounce, так как я использую реализацию lodash. Я думаю, что настройка карт — это именно то, что делает memoize, и поэтому я пытаюсь пойти по этому пути. Любые предложения по этому поводу и почему это не работает? Возможно, по той же причине, что вы сказали, я должен передавать узлы DOM? - person Sunyatasattva; 24.07.2017
comment
@sunyatasattva вам нужно смешать оба, и 5-лайнер, вероятно, более легкий, чем lodash - person Jonas Wilms; 24.07.2017