Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Animation.prototype.finished polyfill
// only polyfill .finished in browsers that already support animate()
if (document.body.animate) {
// Chrome does not seem to expose the Animation constructor globally
if (typeof Animation === 'undefined') {
window.Animation = document.body.animate({}).constructor;
}
if (!('finished' in Animation.prototype)) {
Object.defineProperty(Animation.prototype, 'finished', {
get() {
if (!this._finished) {
this._finished = this.playState === 'finished' ?
Promise.resolve() :
new Promise((resolve, reject) => {
this.addEventListener('finish', resolve, {once: true});
this.addEventListener('cancel', reject, {once: true});
});
}
return this._finished;
}
});
}
}
@davej

This comment has been minimized.

Copy link
Owner Author

davej commented Jul 12, 2019

I was getting an error in Safari 13 (tech preview):

Unhandled Promise Rejection: TypeError: The Animation.finished getter can only be used on instances of Animation

This fork fixes that error.

image

@barneycarroll

This comment has been minimized.

Copy link

barneycarroll commented Aug 29, 2019

Hey @davej, thanks for this!

I tweaked it to use a WeakMap instead of modulos and expose the animation in promise settle states, may be of interest:

// only polyfill .finished in browsers that already support animate()
if (document.body.animate) {
  const finished = new WeakMap()

  // Chrome does not seem to expose the Animation constructor globally
  if (typeof Animation === 'undefined') {
    window.Animation = document.body.animate({}).constructor;
  }

  if (!('finished' in Animation.prototype)) {
    Object.defineProperty(Animation.prototype, 'finished', {
      get() {
        if (finished.has(this))
          return finished.get(this);

        const promise = this.playState === 'finished' ? 
          Promise.resolve() :
          new Promise((resolve, reject) => {
            this.addEventListener('finish', () => {
              resolve(this);
            }, {once: true});
            this.addEventListener('cancel', () => {
              reject(this);
            }, {once: true});
          });
        
        finished.set(this, promise);

        return promise;
      }
    });
  }
}
@davej

This comment has been minimized.

Copy link
Owner Author

davej commented Aug 29, 2019

Thanks @barneycarroll, could you explain the advantages of this approach?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.