我在一个较旧的项目中遇到这个问题已经有一段时间了。我还创建了一个 sample repo在这里,但你可能不需要它。
问题是,我有更多的事件处理程序 Hook 到相同的元素或 Hook 到事件将冒泡的链中的元素。
问题是,一旦第一个处理程序的代码遇到 await(或者当我用 typescript 构建我的代码时遇到 yield),下一个处理程序就会被触发。我如何同步执行以等待第一个处理程序中的所有内容完成,然后才继续执行链上的下一个事件处理程序?
我看到一些示例带有“事件发射器的 promise ”,但我无法控制这里的事件对象,因为它是由浏览器运行时创建的。
我也看到了一些 RxJS 提示,但是谁能给我一个小样本,他是如何解决这个问题的?
一件小事 - 有时我还需要等待另一个按钮点击的完整执行,它可能有自己的事件处理程序链。
最佳答案
有人可能认为这是一种 hack,但您可以在事件对象上构建一个 promise 链:
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>
事件对象是相同的,被传递给每个处理程序。如果您想异步执行其他(后来的)事件处理程序需要依赖的任何操作,请在事件对象上为您的结果存储一个 promise 。然后在等待处理程序中,等待那个特定的 promise 。您还可以使用多个不同的 promise 链,或者如果您希望外部处理程序中的某些事情立即发生,则忽略 promise 。
在 ES8 中,你可以像这样使用 async
/await
:
function handler(e) {
e.innerColorChangeDone = (async () => {
await e.innerColorChangeDone;
await delay(100);
this.style.backgroundColor = …
await delay(100);
})();
}
关于javascript - 如何在浏览器中正确实现异步事件处理程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48688136/