javascript - 如何在浏览器中正确实现异步事件处理程序

标签 javascript asynchronous events ecmascript-6

我在一个较旧的项目中遇到这个问题已经有一段时间了。我还创建了一个 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/

相关文章:

javascript - 为我的discord.js 机器人创建排名列表

node.js - 如何同步向mongo插入数据(Nodejs、Express)

php - 监听 Symfony 2 中的所有事件

javascript - angularjs 添加日期的自定义验证以检查工作日是否在范围内

javascript - 如何从一系列具有相同 id 的文本框中获取值

javascript - 如何在 JavaScript 中使用 LUT?

python - 记录异步调用的正确/常用方法

javascript - RequireJs 定义具有不同路径的模块

jquery - 当用户滚动到 div 时如何做某事?

javascript - 单击前模糊执行