0

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?

2

2 Answers 2

1

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>

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, I was going in this direction but couldn't wrap my mind around the promise resolution within an event listener. It makes me think it would be awesome if one could somehow access an Async Functions's "implicit" promise just like one can access a function's Arguments or Caller.
1

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>

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.