Promises in Web Animations
When I first started learning about the Web Animations API there was one way to handle a “finish” event - the
onfinish callback. It lets you assign it a function and that function is called when the animation is finished.
There is a newer way to handle this scenario, though… via the
finished Promise. This either excites you (if you know what a Promise is), confuses you (if you know what a Promise is), or makes you ask what a Promise is. So…
What is a Promise?
This code starts an animation (by calling
animate() on an element), and any other code will continue to execute while we wait for the animation to enter the “finished” state. Animations will expose a
finished Promise that will “resolve” when the animation finishes. You can think of the Promise as a future object. When it resolves (in this case, a successful finish of the animation), the first function passed into the
then will run. If the animation is rejected (the animation is canceled), it will run the second function passed to
then, if specified.
For rejection, the current spec defines it this way, but there are discussions to change away from this. We will focus on how to work with an animation that resolves for now…
One time fits all
Promises by definition will either resolve or be rejected, and this resolution will only happen once. As soon as a Promise is resolved or rejected, it will not resolve nor reject again. Since animations can be played multiple times, this seems to be at odds with the Web animations API as subsequent finishes would not resolve again.
To solve this, the spec dictates a new Promise will replace the existing
finished Promise when the play state changes to “running”. This allows you to latch on to the Promise resolution state again, but you will have to add your handlers via
Note: As of March 18, 2016 the polyfill has an issue with resolving subsequent finished Promises at the correct time.
Then Why Bother?
Imagine a case where you want to trigger new animations when a given animation finishes. The following example shows two boxes, one using
onfinish to start new animations and the second using the
Callbacks will nest, and Promises can chain by returning a Promise. For this example it reads differently, and one might be more readable than the other to you. In fuller development the chaining can provide more power with how you manage your animation states and values. We will look into that in a future post.
Thanks to Rachel for triggering this discussion and Šime for pointing me to when an animation is rejected in the spec (and Jake for mentioning the discussion about changing that). Thanks also to Martin for recommending additional Promise articles.