resourceloader: Use perf.now() for mediaWikiLoadStart in startup.js
authorTimo Tijhof <krinklemail@gmail.com>
Thu, 9 Feb 2017 21:46:37 +0000 (21:46 +0000)
committerTimo Tijhof <krinklemail@gmail.com>
Thu, 9 Feb 2017 22:03:14 +0000 (22:03 +0000)
Currently we're using 'new Date' which is less accurate for high accuracy
performance measures. On top of that, we are actually using performance.now()
in Navigation Timing to measure mediaWikiLoadEnd, and subsequently
relating it to mediaWikiLoadStart to produce mediaWikiLoadComplete.

Mixing Date and performance.now produces inaccurate results since the
two are usually not in sync. See T153819 for further details.

Solve this by moving the polyfil to startup.js instead.

Also add a basic unit test for mw.now().

Bug: T153819
Change-Id: Ib44538155aa9ba432ec4c58b09ead5333a3a942d

.eslintrc.json
resources/src/mediawiki/mediawiki.js
resources/src/startup.js
tests/qunit/suites/resources/mediawiki/mediawiki.test.js

index 044dd72..98d0f10 100644 (file)
@@ -9,7 +9,6 @@
                "require": false,
                "module": false,
                "mediaWiki": false,
-               "mwPerformance": false,
                "OO": false
        },
        "rules": {
index fceeb64..4df2df7 100644 (file)
@@ -8,6 +8,7 @@
  * @singleton
  */
 
+/* global mwNow */
 /* eslint-disable no-use-before-define */
 
 ( function ( $ ) {
                 *
                 * @return {number} Current time
                 */
-               now: ( function () {
-                       var perf = window.performance,
-                               navStart = perf && perf.timing && perf.timing.navigationStart;
-                       return navStart && typeof perf.now === 'function' ?
-                               function () { return navStart + perf.now(); } :
-                               function () { return +new Date(); };
-               }() ),
+               now: mwNow,
+               // mwNow is defined in startup.js
 
                /**
                 * Format a string. Replace $1, $2 ... $N with positional arguments.
                        return $.when.apply( $, all );
                } );
                loading.then( function () {
+                       /* global mwPerformance */
                        mwPerformance.mark( 'mwLoadEnd' );
                        mw.hook( 'resourceloader.loadEnd' ).fire();
                } );
index 20818d2..deb280a 100644 (file)
@@ -6,11 +6,19 @@
 
 /* global mw, $VARS, $CODE */
 
-// eslint-disable-next-line no-unused-vars
-var mediaWikiLoadStart = ( new Date() ).getTime(),
-       mwPerformance = ( window.performance && performance.mark ) ? performance : {
+var mwPerformance = ( window.performance && performance.mark ) ? performance : {
                mark: function () {}
-       };
+       },
+       // Define now() here to ensure valid comparison with mediaWikiLoadEnd (T153819).
+       mwNow = ( function () {
+               var perf = window.performance,
+                       navStart = perf && perf.timing && perf.timing.navigationStart;
+               return navStart && typeof perf.now === 'function' ?
+                       function () { return navStart + perf.now(); } :
+                       function () { return +new Date(); };
+       }() ),
+       // eslint-disable-next-line no-unused-vars
+       mediaWikiLoadStart = mwNow();
 
 mwPerformance.mark( 'mwLoadStart' );
 
index bac8274..65b7263 100644 (file)
                );
        } );
 
+       QUnit.test( 'mw.now', function ( assert ) {
+               assert.equal( typeof mw.now(), 'number', 'Return a number' );
+               assert.equal(
+                       String( Math.round( mw.now() ) ).length,
+                       String( +new Date() ).length,
+                       'Match size of current timestamp'
+               );
+       } );
+
        QUnit.test( 'mw.Map', function ( assert ) {
                var arry, conf, funky, globalConf, nummy, someValues;