From 9d2e43df757bc783da9d3faad12d5b017c4bb7ba Mon Sep 17 00:00:00 2001 From: Timo Tijhof Date: Mon, 7 May 2018 22:57:40 +0100 Subject: [PATCH] resourceloader: Simplify mwLoadEnd hook implementation In addition to the high overhead of $.Deferred per-module in mw.loader.using(), this was also using $.when() and another Deferred in catch() for casting. The handler for marking mwLoadEnd needs a Promise in our fallback for compatibility with the original using() call. But the code within our fallback does not need to use N promises, for that we can simply use a counter that we decrement, given we only need to worry about completion. So basically, use `Deferred#always(callback)` instead of `Deferred.catch(=>Defered().resolve)).then(callback)`. This is in preparation for moving the code to NavigationTiming. Change-Id: I20514d3fe680fc9384a0f7ce0880652970d86856 --- resources/src/mediawiki/mediawiki.js | 33 ++++++++++++++++------------ 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/resources/src/mediawiki/mediawiki.js b/resources/src/mediawiki/mediawiki.js index 486fb80487..9837ce89ef 100644 --- a/resources/src/mediawiki/mediawiki.js +++ b/resources/src/mediawiki/mediawiki.js @@ -2813,23 +2813,28 @@ * @member mw.hook */ $( function () { - var loading, modules; - - modules = mw.loader.getModuleNames().filter( function ( module ) { + // Get a list of modules currently in loading state + var modules = mw.loader.getModuleNames().filter( function ( module ) { return mw.loader.getState( module ) === 'loading'; } ); - // We only need a callback, not any actual module. First try a single using() - // for all loading modules. If one fails, fall back to tracking each module - // separately via $.when(), this is expensive. - loading = mw.loader.using( modules ).catch( function () { - var all = modules.map( function ( module ) { - return mw.loader.using( module ).catch( function () { - return $.Deferred().resolve(); - } ); + // Wait for them to complete loading (regardles of failures). First, try a single + // mw.loader.using() call. That's efficient, but has the drawback of being rejected + // upon first failure. Fall back to tracking each module separately. We usually avoid + // that because of high overhead for that internally to mw.loader. + mw.loader.using( modules ).catch( function () { + return $.Deferred( function ( deferred ) { + var i, count = modules.length; + function decrement() { + count--; + if ( count === 0 ) { + deferred.resolve(); + } + } + for ( i = 0; i < modules.length; i++ ) { + mw.loader.using( modules[ i ] ).always( decrement ); + } } ); - return $.when.apply( $, all ); - } ); - loading.then( function () { + } ).then( function () { if ( window.performance && performance.mark ) { performance.mark( 'mwLoadEnd' ); } -- 2.20.1