Reputation: 2364
Consider this 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
}
}
Is there any way to deal with this scenario, and actually have an async function resolve/return upon an event listener callback?
Upvotes: 0
Views: 1124
Reputation: 136678
You could return or await a new Promise inside your async function and call its resolver in the event handler, but the thing with most events (and animationend is part of it) is that they may never fire, so you could be awaiting for something that will never happen.
In this particular case of an animationend, you can solve this issue thanks to the Web-Animations API which exposes a finished
Promise that will either resolve or reject if the animation got stopped before its expected end:
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>
Upvotes: 1
Reputation: 207501
Use a promise. In the animationend event listener, resolve it.
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>
Upvotes: 1