Я борюсь с этой проблемой в более раннем проекте, который у меня есть на некоторое время. Я также создал образец репо здесь, но вы, возможно, не нуждаетесь в нем.
Проблема в том, что у меня больше обработчиков событий, подключенных к тем же элементам или подключенных к элементу в цепочке, где событие будет пузыриться.
Проблема в том, что после того, как код первого обработчика встретится (или уступит, когда я создам код с машинописным текстом), запускается следующий обработчик. Как синхронизировать выполнение, чтобы подождать, пока все в первом обработчике не закончится и только затем продолжит следующий обработчик событий в цепочке?
Я видел несколько примеров с "promisification event emitter", но я не контролирую объект события здесь, так как он создан во время выполнения браузера.
Также я видел некоторые подсказки RxJS, но может ли кто-нибудь дать мне небольшой образец, как ему удалось исправить эту проблему?
Одна маленькая вещь - иногда мне также нужно ждать целого выполнения другого нажатия кнопки, у которого может быть цепочка собственных обработчиков событий.
Можно подумать, что это взлом, но вы можете построить цепочку обещаний для объекта события:
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);
})();
}