Page MenuHomePhabricator

jquery.makeCollapsible: FOUC caused by collapsible message box on start of page
Closed, DuplicatePublic

Description

Example page https://en.wikipedia.org/wiki/Many-valued_logic
FOUC happens 1~2 seconds even with a decent network connection.
This happens (I guess) because message box is collapsed after document load event, which takes time because it requires every images to be loaded.

Before loaded:
https://phab.wmfusercontent.org/file/data/hgi5ea4zddl5mr4vwyx7/PHID-FILE-sw6gre5pgrouacy6rw4b/message-box-FOUC-1

After loaded:
https://phab.wmfusercontent.org/file/data/hp6yppfpajmnaxmi5sbv/PHID-FILE-vkxejf7rih2bkzlnrfhf/message-box-FOUC-2

Event Timeline

This is probably a known bug in jQuery 1.11 (the version currently in use by WMF), fixed in jQuery 1.12 and later. If the first use of jQuery.ready.promise() comes after the browser has fired the DOMContentLoaded event (or readyState === 'interactive'), jQuery will incorrectly wait until the load event (or readyState === 'complete').

DOMContentLoaded / interactive is when the DOM is ready for action, but before other resources have finished loading.

load / complete is when everything is done.

jQuery.ready is intended to align to the earlier of the two states, and will do so (in 1.11) if jQuery.ready.promise() is first called before the event fires, but not if it is called afterwards. If desired, the fix is quite small and would be quite easy to back port to jQuery 1.11.

See the diff between jQuery 1.11 and 1.12 for src/core/ready.js

The bug is due to a workaround for junk quality, non-compliant implementation of JS in older MS-IE. Older MS-IE is stuck with the event firing late (including with the fixed jQuery code), due to its bad implementation.

I can reproduce the FOUC, which has been around for years. However I'm fairly certain that we do correctly trigger this and all other domready-scheduled work at DOMContentLoaded. We've got plenty of early calls to $.ready. And once that promise starts, it is resolved and remembered.

The FOUC issue is filed as T42812 and requires a change to its logic to use CSS instead of run-time JavaScript to perform the initial hide of elements collapsed by default. There is agreement about that direction, but a patch still needs to be written/reviewed.

Regarding jQuery 1.11, we've already begun preparations for upgrading to jQuery 3. Most blockers have been resolved. Should be in production in a couple more weeks.

Since we'll use the jQuery Migrate plugin at first, the upgrade should be fairly smooth. However there are a number of undocumented behaviours that changed in jQuery 3 that did affect a fair number of our components. Specifically there were a number of modules in our code bases that unfortunately made assumptions about jQuery deferred handlers being called synchronously if a deferred is already resolved.

T124742: Upgrade to jQuery 3

Krinkle renamed this task from FOUC caused by collapsible message box on start of page to jquery.makeCollapsible: FOUC caused by collapsible message box on start of page.Jun 14 2017, 9:35 PM

Testing the behaviour on enwiki and meta (actually a few days ago, when I had cause to investigate why my user JS was sometimes slow to fire), the first call to jQuery.ready.promise() frequently occurs after DOMContentLoaded, adding the undesirable delay. I see (jQuery.isReady === false) long after DOMContentLoaded has fired.

As far as fixing it for jQuery 1.x or getting the fix as part of the jQuery 3 upgrade, jQuery 3 is fine by me (and a welcome upgrade), especially if it's imminent.