DOM 异步函数内的事件回调

DOM event callback within async function

考虑这个功能

async function Animate(element)
{
 // do something with dom element's animation, triggering it
  
 element.addEventListener("animationend", 
 function(event)
 {
  // this is when Animate(element) should resolve/return
 }

}

有没有办法处理这种情况,并且在事件侦听器回调时实际上有一个异步函数resolve/return?

使用承诺。在animationend事件监听器中解析。

const animateThis = async(elem) => {
  return new Promise(resolve => {
    elem.classList.add("active");
    elem.addEventListener('animationend', () => {
      elem.classList.remove("active");
      resolve();
    });
  });
};

(async function() {
  const elem = document.querySelector(".animation");
  console.log("before call");
  await animateThis(elem);
  console.log("after call");
}());
.animation.active {
  animation-duration: 2s;
  animation-name: slidein;
  animation-iteration-count: 2;
}

@keyframes slidein {
  from {
    margin-left: 100%;
    width: 300%;
  }
  to {
    margin-left: 0%;
    width: 100%;
  }
}
<p class="animation">Hello World</p>

您可以 return 或在您的异步函数中等待一个新的 Promise 并在事件处理程序中调用它的解析器,但是大多数事件(动画结束是其中的一部分)的问题是它们可能永远不会触发,所以您可能正在等待永远不会发生的事情。

在 animationend 的这种特殊情况下,由于 Web-Animations API which exposes a finished 如果动画在预期结束前停止,Promise 将解决或拒绝,您可以解决此问题:

const elem = document.querySelector(".animate");
(async () => {
  // never gonna resolve
  const prom = new Promise((resolve) => {
    elem.addEventListener("animationend", () => resolve(), { once: true });
  });
  // await prom;
  prom.then(()=>console.log("event fired"));

  // using the Web Animation API
  // we should do more filtering on the Animations here
  // to be sure we get our own
  const anim = elem.getAnimations()[0];
  try {
    await anim.finished;
  }
  catch(err) { }
  console.log("anim ended");
})().catch(console.error);
// stop the animation before completion
setTimeout(() => elem.remove(), 2000);
.animate {
  width: 50px;
  height: 50px;
  background: green;
  animation: anim 10s linear;
}
@keyframes anim {
  to {
    transform: translate(120px,0);
  }
}
<div class="animate"></div>