<div dir="ltr"><div>Might be useful to list somewhere on the frontend practices page, especially so these caveats are captured.<br></div><div><br></div><div><a href="https://developer.mozilla.org/en-US/Firefox/Performance_best_practices_for_Firefox_fe_engineers">https://developer.mozilla.org/en-US/Firefox/Performance_best_practices_for_Firefox_fe_engineers</a></div><div><br></div>- Ryan</div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Aug 2, 2017 at 2:11 PM, Kris Maglione <span dir="ltr"><<a href="mailto:kmaglione@mozilla.com" target="_blank">kmaglione@mozilla.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">In bug 1383367, I landed a set of new helpers to make it possible to query the layout state (e.g., element size and position, or computed style such as color) without forcing an uninterruptible reflow.<br>
<br>
Note: Please read on for caveats before jumping into using this.<br>
<br>
The one that you probably really care about is promiseLayoutFlushed[1], which is in a lot of ways the converse of (and complement to) requestAnimationFrame. Its use looks something like this:<br>
<br>
let width = await BrowserUtils.promiseLayoutFlus<wbr>hed(document, "layout", () => {<br>
return elem.clientWidth;<br>
});<br>
<br>
requestAnimationFrame(() => {<br>
otherElem.style.width = `${width - 2*borderWidth}px`;<br>
});<br>
<br>
This will cause the layout width of an element to be queried as soon as that's possible without a reflow (which may be immediately, or just after some other code queries the layout state, or just after the next paint), and then uses that width to update the DOM in the next animation frame.<br>
<br>
Essentially, as long as your `promiseLayoutFlushed` callback queries the layout *but never alters the DOM*, and your requestAnimationFrame callbacks alter the DOM *but never query the layout*, all queries and updates should happen in groups, and we shouldn't have any uninterruptible reflows. In theory, either of these things on their own should be enough to guarantee that, but in practice, we have a lot of legacy code that doesn't follow those rules, so this is another tool in our toolbox to get us close to that ideal.<br>
<br>
<br>
Important caveats: *Please* be careful how you use this. And especially keep in mind that there may need to be a paint before your promise resolves and any dependent DOM updates happen. If you're not absolutely sure that that won't result in glitchy UI behavior, *please test carefully* to make sure that it doesn't.<br>
<br>
At the moment, the implementation is fairly crude, and any callbacks which need to be deferred happen after the next full reflow, even if a full reflow isn't required. And there's no way to force deferred callbacks to be handled before the next paint aside from forcing a layout flush. It should be possible in the future, though, to schedule an interruptible reflow just before the next animation frame in cases where we know that's required, and trigger our deferred callbacks before paint. If you have a particular need for that, please let me know and I may be able to make it a higher priority.<br>
<br>
<br>
<br>
[1]: <a href="https://dxr.mozilla.org/mozilla-central/rev/ef9a0f01e4f68214f0ff8f4631783b8a0e075a82/toolkit/modules/BrowserUtils.jsm#702-729" rel="noreferrer" target="_blank">https://dxr.mozilla.org/mozill<wbr>a-central/rev/ef9a0f01e4f68214<wbr>f0ff8f4631783b8a0e075a82/<wbr>toolkit/modules/BrowserUtils.<wbr>jsm#702-729</a><br>
______________________________<wbr>_________________<br>
firefox-dev mailing list<br>
<a href="mailto:firefox-dev@mozilla.org" target="_blank">firefox-dev@mozilla.org</a><br>
<a href="https://mail.mozilla.org/listinfo/firefox-dev" rel="noreferrer" target="_blank">https://mail.mozilla.org/listi<wbr>nfo/firefox-dev</a><br>
</blockquote></div><br></div>