Идеальный способ условного расписания задач для requestAnimationFrame (с использованием fastdom) - PullRequest
1 голос
/ 10 июля 2020

У меня есть сценарий, который я считаю немного сложным: я хочу запланировать свои изменения в DOM, используя requestAnimationFrame (rAF), но у меня есть много условных c logi, которые я должен учитывать .

Рассмотрим это:

function writeToDOM(cb) {
  fastdom.mutate(cb);
}

function performLogicThatDoesntUpdateTheDOM() {
  // stuff I need to do with each touchmove event
  // these things don't update the DOM, but they need to run
  // after checking if the DOM needs to be updated
}

document.body.addEventListener('touchmove', event => {
  if (propertyHasChanged) {
    writeToDOM(function() {
      someNode.classList.add('changed');
    });
  }

  performLogicThatDoesntUpdateTheDOM();

  if (anotherPropertyHasChanged) {
    writeToDOM(function() {
      anotherNode.classList.add('changed-too');
    });
  }
});

Идея состоит в том, что у меня есть функция-оболочка (writeToDOM), которая принимает обратный вызов и ставит в очередь этот обратный вызов для выполнения в следующем доступном requestAnimationFrame, используя библиотека fastdom .

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

Я уже пробовал что-то вроде этого:

let writesAreScheduled = false;
document.body.addEventListener('touchmove', event => {
  if (writesAreScheduled) {
    // don't do anything
    return;
  }
  if (propertyHasChanged) {
    writeToDOM(function() {
      writesAreScheduled = false;
      someNode.classList.add('changed');
    });
    writesAreScheduled = true;
  }

  performLogicThatDoesntUpdateTheDOM();

  if (anotherPropertyHasChanged) {
    writeToDOM(function() {
      writesAreScheduled = false;
      anotherNode.classList.add('changed-too');
    });
    writesAreScheduled = true;
  }
});

Проблема с этим подходом в том, что он не позволяет мне запускать performLogicThatDoesntUpdateTheDOM после того, как запланировано обновление.

Итак, как я могу ограничить только обновления DOM, но всегда запускать другие мои logi c? Я не хочу ограничивать весь обработчик touchmove, только ту часть, которая обновляет DOM. У меня есть идея сделать что-то вроде этого:

let writesAreScheduled = false;
document.body.addEventListener('touchmove', event => {
  const taskQueue = [];
  if (propertyHasChanged) {
    taskQueue.push(function() {
      writesAreScheduled = false;
      someNode.classList.add('changed');
    });
  }

  performLogicThatDoesntUpdateTheDOM();

  if (anotherPropertyHasChanged) {
    taskQueue.push(function() {
      writesAreScheduled = false;
      anotherNode.classList.add('changed-too');
    });
  }

  // only schedule DOM updates if none are currently scheduled
  if (!writesAreScheduled) {
    taskQueue.forEach(task => writeToDOM(task));
    writesAreScheduled = true;
  }
});

По сути, я храню массив обновлений DOM, которые необходимо выполнить, как только я определю, что они должны произойти. Затем, после выполнения всех определений, я проверяю флаг, чтобы увидеть, есть ли уже запланированный rAF, чтобы убедиться, что я планирую только один за раз. Помните, что моя цель - ограничить только частоту обновлений DOM, но запускать другие logi c так же часто, как срабатывает событие touchmove.

Я еще не реализовал это, и фактический код я Я работаю, это намного сложнее, поэтому мне не удалось создать более простую копию. У кого-нибудь есть другое / лучшее представление о том, как это сделать? Спасибо!

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