как правильно реализовать асинхронные обработчики событий в браузере

1

Я борюсь с этой проблемой в более раннем проекте, который у меня есть на некоторое время. Я также создал образец репо здесь, но вы, возможно, не нуждаетесь в нем.

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

Проблема в том, что после того, как код первого обработчика встретится (или уступит, когда я создам код с машинописным текстом), запускается следующий обработчик. Как синхронизировать выполнение, чтобы подождать, пока все в первом обработчике не закончится и только затем продолжит следующий обработчик событий в цепочке?

Я видел несколько примеров с "promisification event emitter", но я не контролирую объект события здесь, так как он создан во время выполнения браузера.

Также я видел некоторые подсказки RxJS, но может ли кто-нибудь дать мне небольшой образец, как ему удалось исправить эту проблему?

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

  • 0
    Почему у вас есть несколько разных слушателей событий, когда они тесно связаны?
  • 0
    действительно хороший вопрос. Ответ прост, тонны устаревшего кода, который я должен исправить, сэр.
Показать ещё 2 комментария
Теги:
ecmascript-6
asynchronous
events

1 ответ

1
Лучший ответ

Можно подумать, что это взлом, но вы можете построить цепочку обещаний для объекта события:

function delay(t) {
  return new Promise(resolve => { setTimeout(resolve, t); });
}
function handler(e) {
  e.innerColorChangeDone = Promise.resolve(e.innerColorChangeDone) // might be undefined
    .then(() => delay(100))
    .then(() => {
      this.style.backgroundColor = "#"+Array.from({length:3}, () =>
        Math.round(Math.random()*5+9).toString(16)
      ).join("");
      return delay(100);
    });
}
for (const el of document.getElementsByTagName("div"))
  el.onclick = handler;
div {
  padding: 1em;
  border: solid 1px #aaa;
  width: fit-content;
}
<div>
  <div>
    <div>
      <div>
        Click!
      </div>
    </div>
  </div>
</div>

Объект события тот же, который передается каждому из обработчиков. Если вы хотите сделать что-либо асинхронным, чтобы другой (более поздний) обработчик событий должен был зависеть, сохраните обещание для вашего результата в объекте события. Затем в ожидающем обработчике дождитесь этого конкретного обещания. Вы также можете использовать несколько разных цепочек обещаний или игнорировать обещание, если хотите, чтобы что-то в внешнем обработчике произошло немедленно.

В ES8 вы можете использовать async/await следующим образом:

function handler(e) {
  e.innerColorChangeDone = (async () => {
    await e.innerColorChangeDone;
    await delay(100);
    this.style.backgroundColor = …
    await delay(100);
  })();
}
  • 0
    Спасибо, сэр! работает как шарм !!! Я повторил что-то подобное, но ваш пример лучше! Еще раз спасибо! теперь другая часть проблемы: как я мог вызвать другой элемент с его собственной цепочкой обработчиков событий, привязанных к нему, но ждать выполнения их всех, когда обработчики возвращаются по умолчанию void? Кажется, я не могу передать свой объект события в HTMLElement.onclick () в качестве параметра, поскольку .onclick () не имеет никакого входного параметра. Спасибо
  • 0
    Конечно, вы можете запускать свои собственные события (и снова ждать обещания для объекта события после запуска обработчиков), но звучит так, как будто вы хотите подождать, пока пользователь нажмет несколько кнопок. Для этого вам нужно поддерживать некоторое состояние в вашем приложении, вы не можете сделать это только с помощью обработчиков событий.
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню