mediawiki.notification: Move offset() computation to next frame
authorTimo Tijhof <krinklemail@gmail.com>
Wed, 4 Oct 2017 20:30:24 +0000 (21:30 +0100)
committerJames D. Forrester <jforrester@wikimedia.org>
Wed, 4 Oct 2017 21:41:25 +0000 (14:41 -0700)
Crrently on all page views in WMF production, the $.ready handler
is inserting the notif $area and subsequently doing a forced
style calculation due to getBoundingClientRect() from offset().

Move this to an animation frame instead and re-order the statements
so that DOM reads go before DOM writes.

Change-Id: I7c6201dc8d4e3227e01b75e853b6e4dc9a734031

resources/src/mediawiki/mediawiki.notification.js

index d5289bd..20f8b8d 100644 (file)
                                .toggleClass( 'mw-notification-area-layout', !isFloating );
                }
 
+               // Write to the DOM:
                // Prepend the notification area to the content area and save its object.
                $area = $( '<div id="mw-notification-area" class="mw-notification-area mw-notification-area-layout"></div>' )
                        // Pause auto-hide timers when the mouse is in the notification area.
                        } );
 
                mw.util.$content.prepend( $area );
-               offset = $area.offset();
-               $area.css( 'display', 'none' );
 
-               $( window ).on( 'scroll', updateAreaMode );
+               // Read from the DOM:
+               // Must be in the next frame to avoid synchronous layout
+               // computation from offset()/getBoundingClientRect().
+               rAF( function () {
+                       offset = $area.offset();
 
-               // Initial mode
-               updateAreaMode();
+                       // Initial mode (reads, and then maybe writes)
+                       updateAreaMode();
 
-               // Handle pre-ready queue.
-               isPageReady = true;
-               while ( preReadyNotifQueue.length ) {
-                       notif = preReadyNotifQueue.shift();
-                       notif.start();
-               }
+                       // Once we have the offset for where it would normally render, set the
+                       // initial state of the (currently empty) notification area to be hidden.
+                       $area.css( 'display', 'none' );
+
+                       $( window ).on( 'scroll', updateAreaMode );
+
+                       // Handle pre-ready queue.
+                       isPageReady = true;
+                       while ( preReadyNotifQueue.length ) {
+                               notif = preReadyNotifQueue.shift();
+                               notif.start();
+                       }
+               } );
        }
 
        /**