Bug 1356532: Part 1 - Add BrowserUtils.promiseAnimationFrame helper. r=florian draft
authorKris Maglione <maglione.k@gmail.com>
Mon, 24 Jul 2017 20:08:27 -0700
changeset 656126 ff644f860c0be5d19446c89827fc234a0e60d25f
parent 653623 eca521df662fffe4d3b6de833a01a5f152a3db6e
child 656127 88f47d0399e33cec779c2172c17c89975e7f5315
push id77076
push usermaglione.k@gmail.com
push dateWed, 30 Aug 2017 19:02:00 +0000
reviewersflorian
bugs1356532, 1193394
milestone57.0a1
Bug 1356532: Part 1 - Add BrowserUtils.promiseAnimationFrame helper. r=florian It's important that requestAnimationFrame callbacks run synchronously, and carefully control what code runs during them. At the same time, we often need UI code that runs before and after the DOM mutations in an animation frame callback. This helper makes it possible to run DOM mutation code during an animation frame in the course of an async function, and then resume execution after the animation frame callback has been executed, and without danger of blocking the frame from being painted. It's also important to note that, at the moment, the promise microtask queue is not flushed at the end of the animation frame callback, which means we can safely rely on promise resolution handlers automatically executing after frame has been painted. After bug 1193394 is fixed, that will no longer be the case, and we'll need to resolve the promise from a task dispatched to the event loop. MozReview-Commit-ID: H5MHWKuLf3O
toolkit/modules/BrowserUtils.jsm
--- a/toolkit/modules/BrowserUtils.jsm
+++ b/toolkit/modules/BrowserUtils.jsm
@@ -720,9 +720,33 @@ this.BrowserUtils = {
                    .getInterface(Ci.nsIDOMWindowUtils);
 
     if (!utils.needsFlush(FLUSH_TYPES[flushType])) {
       return callback();
     }
 
     return this.promiseReflowed(doc, callback);
   },
+
+  /**
+   * Calls the given callback on the next animation frame for the given
+   * window, and resolves with its return value after it's been
+   * executed.
+   *
+   * The callback function may alter the DOM freely, but *must not query the document's style or
+   * layout state*.
+   *
+   * @param {Window} win
+   * @param {function} callback
+   * @returns {Promise}
+   */
+  promiseAnimationFrame(win, callback) {
+    return new Promise((resolve, reject) => {
+      win.requestAnimationFrame(timestamp => {
+        try {
+          resolve(callback(timestamp));
+        } catch (e) {
+          reject(e);
+        }
+      });
+    });
+  },
 };