Merge "resourceloader: Remove module stringification from execute path"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Tue, 4 Sep 2018 18:55:56 +0000 (18:55 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Tue, 4 Sep 2018 18:55:56 +0000 (18:55 +0000)
1  2 
resources/src/startup/mediawiki.js

@@@ -1,7 -1,7 +1,7 @@@
  /**
   * Base library for MediaWiki.
   *
 - * Exposed globally as `mediaWiki` with `mw` as shortcut.
 + * Exposed globally as `mw`, with `mediaWiki` as alias.
   *
   * @class mw
   * @alternateClassName mediaWiki
                log.deprecate = !Object.defineProperty ? function ( obj, key, val ) {
                        obj[ key ] = val;
                } : function ( obj, key, val, msg, logName ) {
 -                      var logged = new StringSet();
 -                      logName = logName || key;
 -                      msg = 'Use of "' + logName + '" is deprecated.' + ( msg ? ( ' ' + msg ) : '' );
 -                      function uniqueTrace() {
 -                              var trace = new Error().stack;
 -                              if ( logged.has( trace ) ) {
 -                                      return false;
 +                      var stacks;
 +                      function maybeLog() {
 +                              var name,
 +                                      trace = new Error().stack;
 +                              if ( !stacks ) {
 +                                      stacks = new StringSet();
 +                              }
 +                              if ( !stacks.has( trace ) ) {
 +                                      stacks.add( trace );
 +                                      name = logName || key;
 +                                      mw.track( 'mw.deprecate', name );
 +                                      mw.log.warn(
 +                                              'Use of "' + name + '" is deprecated.' + ( msg ? ( ' ' + msg ) : '' )
 +                                      );
                                }
 -                              logged.add( trace );
 -                              return true;
                        }
                        // Support: Safari 5.0
                        // Throws "not supported on DOM Objects" for Node or Element objects (incl. document)
                                        configurable: true,
                                        enumerable: true,
                                        get: function () {
 -                                              if ( uniqueTrace() ) {
 -                                                      mw.track( 'mw.deprecate', logName );
 -                                                      mw.log.warn( msg );
 -                                              }
 +                                              maybeLog();
                                                return val;
                                        },
                                        set: function ( newVal ) {
 -                                              if ( uniqueTrace() ) {
 -                                                      mw.track( 'mw.deprecate', logName );
 -                                                      mw.log.warn( msg );
 -                                              }
 +                                              maybeLog();
                                                val = newVal;
                                        }
                                } );
                         *   - resolve: failed to sort dependencies for a module in mw.loader.load
                         *   - store-eval: could not evaluate module code cached in localStorage
                         *   - store-localstorage-init: localStorage or JSON parse error in mw.loader.store.init
-                        *   - store-localstorage-json: JSON conversion error in mw.loader.store.set
-                        *   - store-localstorage-update: localStorage or JSON conversion error in mw.loader.store.update
+                        *   - store-localstorage-json: JSON conversion error in mw.loader.store
+                        *   - store-localstorage-update: localStorage conversion error in mw.loader.store.
                         */
  
                        /**
  
                                // The current module became 'ready'.
                                if ( registry[ module ].state === 'ready' ) {
-                                       // Save it to the module store.
-                                       mw.loader.store.set( module, registry[ module ] );
+                                       // Queue it for later syncing to the module store.
+                                       mw.loader.store.add( module );
                                        // Recursively execute all dependent modules that were already loaded
                                        // (waiting for execution) and no longer have unsatisfied dependencies.
                                        for ( m in registry ) {
                                        // Allow multiple registration
                                        if ( typeof module === 'object' ) {
                                                resolveIndexedDependencies( module );
 +                                              // module is an array of arrays
                                                for ( i = 0; i < module.length; i++ ) {
                                                        // module is an array of module names
 -                                                      if ( typeof module[ i ] === 'string' ) {
 -                                                              mw.loader.register( module[ i ] );
 -                                                      // module is an array of arrays
 -                                                      } else if ( typeof module[ i ] === 'object' ) {
 -                                                              mw.loader.register.apply( mw.loader, module[ i ] );
 -                                                      }
 +                                                      mw.loader.register.apply( mw.loader, module[ i ] );
                                                }
                                                return;
                                        }
                                                mw.loader.register( name );
                                        }
                                        // Check for duplicate implementation
 -                                      if ( hasOwn.call( registry, name ) && registry[ name ].script !== undefined ) {
 +                                      if ( registry[ name ].script !== undefined ) {
                                                throw new Error( 'module already implemented: ' + name );
                                        }
                                        if ( version ) {
                                        // to module implementations.
                                        items: {},
  
+                                       // Names of modules to be stored during the next update.
+                                       // See add() and update().
+                                       queue: [],
                                        // Cache hit stats
                                        stats: { hits: 0, misses: 0, expired: 0, failed: 0 },
  
                                        },
  
                                        /**
-                                        * Stringify a module and queue it for storage.
+                                        * Queue the name of a module that the next update should consider storing.
                                         *
+                                        * @since 1.32
                                         * @param {string} module Module name
-                                        * @param {Object} descriptor The module's descriptor as set in the registry
                                         */
-                                       set: function ( module, descriptor ) {
-                                               var args, key, src;
+                                       add: function ( module ) {
                                                if ( !this.enabled ) {
                                                        return;
                                                }
+                                               this.queue.push( module );
+                                               this.requestUpdate();
+                                       },
+                                       /**
+                                        * Add the contents of the named module to the in-memory store.
+                                        *
+                                        * This method does not guarantee that the module will be stored.
+                                        * Inspection of the module's meta data and size will ultimately decide that.
+                                        *
+                                        * This method is considered internal to mw.loader.store and must only
+                                        * be called if the store is enabled.
+                                        *
+                                        * @private
+                                        * @param {string} module Module name
+                                        */
+                                       set: function ( module ) {
+                                               var key, args, src,
+                                                       descriptor = mw.loader.moduleRegistry[ module ];
  
                                                key = getModuleKey( module );
  
                                                        // Already stored a copy of this exact version
                                                        key in this.items ||
                                                        // Module failed to load
+                                                       !descriptor ||
                                                        descriptor.state !== 'ready' ||
                                                        // Unversioned, private, or site-/user-specific
                                                        !descriptor.version ||
                                                        return;
                                                }
                                                this.items[ key ] = src;
-                                               this.update();
                                        },
  
                                        /**
                                        },
  
                                        /**
-                                        * Sync in-memory store back to localStorage.
+                                        * Request a sync of the in-memory store back to persisted localStorage.
                                         *
                                         * This function debounces updates. When called with a flush already pending, the
                                         * scheduled flush is postponed. The call to localStorage.setItem will be keep
                                         * is minor (merely a less efficient cache use) and the problem would be corrected
                                         * by subsequent page views.
                                         *
+                                        * This method is considered internal to mw.loader.store and must only
+                                        * be called if the store is enabled.
+                                        *
+                                        * @private
                                         * @method
                                         */
-                                       update: ( function () {
+                                       requestUpdate: ( function () {
                                                var timer, hasPendingWrites = false;
  
                                                function flushWrites() {
                                                        var data, key;
-                                                       if ( !mw.loader.store.enabled ) {
-                                                               return;
-                                                       }
  
+                                                       // Remove anything from the in-memory store that came from previous page
+                                                       // loads that no longer corresponds with current module names and versions.
                                                        mw.loader.store.prune();
+                                                       // Process queued module names, serialise their contents to the in-memory store.
+                                                       while ( mw.loader.store.queue.length ) {
+                                                               mw.loader.store.set( mw.loader.store.queue.shift() );
+                                                       }
                                                        key = mw.loader.store.getStoreKey();
                                                        try {
                                                                // Replacing the content of the module store might fail if the new
                                                }
  
                                                function request() {
-                                                       // If another mw.loader.store.set()/update() call happens in the narrow
+                                                       // If another mw.loader.store.requestUpdate() call happens in the narrow
                                                        // time window between requestIdleCallback() and flushWrites firing, ignore it.
                                                        // It'll be saved by the already-scheduled flush.
                                                        if ( !hasPendingWrites ) {