Bug 1353013 - Be less aggressive about preloading about:newtab. r=florian
☠☠ backed out by 5ea49e6b1af6 ☠ ☠
authorMike Conley <mconley@mozilla.com>
Thu, 24 Aug 2017 15:23:18 -0700
changeset 428520 5d320d8864e90aa9684462251fee5b60f055ea9b
parent 428519 cf5b68506bef58600c4e8ec1654102fd36bf0c52
child 428521 52b106ba3e95059cba7da9c22b3165753d40b3ae
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersflorian
bugs1353013
milestone57.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1353013 - Be less aggressive about preloading about:newtab. r=florian Based on a patch that Dão Gottwald <dao+bmo@mozilla.com> wrote. We used to preload about:newtab as soon as a tab had finished being opened, which meant that the first opened tab was _never_ preloaded, and that we risked janking the browser immediately after the user opened a new tab (which is, arguably, the worst time to do it, since the user is probably about to navigate that tab somewhere). This patch makes it so that about:newtab is preloaded after: 1) 1 second of user inactivity, and 2) When we have at least 40ms of idle time to spend in an idle callback. The 1s and 40ms thresholds were chosen arbitrarily, and we might tune them over time. MozReview-Commit-ID: J5xkPQvCdW6
browser/base/content/browser.js
browser/base/content/tabbrowser.xml
toolkit/modules/Services.jsm
toolkit/modules/tests/xpcshell/test_Services.js
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1585,16 +1585,19 @@ var gBrowserInit = {
     gBrowser.tabContainer.addEventListener("TabSelect", function() {
       for (let panel of document.querySelectorAll("panel[tabspecific='true']")) {
         if (panel.state == "open") {
           panel.hidePopup();
         }
       }
     });
 
+    // Prepare preloaded browser for the next new tab to open.
+    gBrowser.requestPreloadBrowser();
+
     this.delayedStartupFinished = true;
 
     _resolveDelayedStartup();
 
     SessionStore.promiseAllWindowsRestored.then(() => {
       this._schedulePerWindowIdleTasks();
       document.documentElement.setAttribute("sessionrestored", "true");
     });
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -2094,25 +2094,65 @@
             // and the URL is "about:newtab". We do not support preloading for
             // custom newtab URLs.
             return Services.prefs.getBoolPref("browser.newtab.preload") &&
                    !aboutNewTabService.overridden;
           ]]>
         </body>
       </method>
 
+      <field name="_preloadBrowserMinUserIdleSeconds">1</field>
+      <field name="_preloadBrowserMinIdlePeriodMs">40</field>
+      <method name="requestPreloadBrowser">
+        <body><![CDATA[
+          // Do nothing if we have a preloaded browser already or we're about
+          // to create one or preloading is disabled.
+          if (this._preloadedBrowser ||
+              this._preloadBrowserIdleObserver ||
+              !this._isPreloadingEnabled()) {
+            return;
+          }
+
+          this._preloadBrowserIdleObserver = (aSubject, aTopic) => {
+            if (aTopic != "idle") {
+              return;
+            }
+
+            Services.idle.removeIdleObserver(this._preloadBrowserIdleObserver,
+                                             this._preloadBrowserMinUserIdleSeconds);
+            this._preloadBrowserIdleObserver = null;
+
+            let idleCallback = deadline => {
+              if (deadline.timeRemaining() < this._preloadBrowserMinIdlePeriodMs) {
+                window.requestIdleCallback(idleCallback);
+              } else {
+                this._createPreloadBrowser();
+              }
+            };
+            window.requestIdleCallback(idleCallback);
+          };
+          Services.idle.addIdleObserver(this._preloadBrowserIdleObserver, this._preloadBrowserMinUserIdleSeconds);
+        ]]></body>
+      </method>
+
       <method name="_createPreloadBrowser">
         <body>
           <![CDATA[
             // Do nothing if we have a preloaded browser already
             // or preloading of newtab pages is disabled.
             if (this._preloadedBrowser || !this._isPreloadingEnabled()) {
               return;
             }
 
+            if (this._preloadBrowserIdleObserver) {
+              Services.idle.removeIdleObserver(this._preloadBrowserIdleObserver,
+                                               this._preloadBrowserMinUserIdleSeconds);
+              this._preloadBrowserIdleObserver = null;
+            }
+
             let remoteType =
               E10SUtils.getRemoteTypeForURI(BROWSER_NEW_TAB_URL,
                                             gMultiProcessBrowser);
             let browser = this._createBrowser({isPreloadBrowser: true, remoteType});
             this._preloadedBrowser = browser;
 
             let notificationbox = this.getNotificationBox(browser);
             this.mPanelContainer.appendChild(notificationbox);
@@ -5849,16 +5889,22 @@
             window.messageManager.removeMessageListener("contextmenu", this);
 
             if (this._switcher) {
               this._switcher.destroy();
             }
           }
 
           Services.prefs.removeObserver("accessibility.typeaheadfind", this);
+
+          if (this._preloadBrowserIdleObserver) {
+            Services.idle.removeIdleObserver(this._preloadBrowserIdleObserver,
+                                             this._preloadBrowserMinUserIdleSeconds);
+            this._preloadBrowserIdleObserver = null;
+          }
         ]]>
       </destructor>
 
       <field name="_soundPlayingAttrRemovalTimer">0</field>
       <field name="_hoverTabTimer">null</field>
     </implementation>
 
     <handlers>
@@ -6920,17 +6966,17 @@
           // XXXmano: this is a temporary workaround for bug 345399
           // We need to manually update the scroll buttons disabled state
           // if a tab was inserted to the overflow area or removed from it
           // without any scrolling and when the tabbar has already
           // overflowed.
           this.mTabstrip._updateScrollButtonsDisabledState();
 
           // Preload the next about:newtab if there isn't one already.
-          this.tabbrowser._createPreloadBrowser();
+          this.tabbrowser.requestPreloadBrowser();
         ]]></body>
       </method>
 
       <method name="_canAdvanceToTab">
         <parameter name="aTab"/>
         <body>
         <![CDATA[
           return !aTab.closing;
--- a/toolkit/modules/Services.jsm
+++ b/toolkit/modules/Services.jsm
@@ -72,16 +72,17 @@ var initTable = {
   cache2: ["@mozilla.org/netwerk/cache-storage-service;1", "nsICacheStorageService"],
   cpmm: ["@mozilla.org/childprocessmessagemanager;1", "nsIMessageSender"],
   console: ["@mozilla.org/consoleservice;1", "nsIConsoleService"],
   cookies: ["@mozilla.org/cookiemanager;1", "nsICookieManager2"],
   downloads: ["@mozilla.org/download-manager;1", "nsIDownloadManager"],
   droppedLinkHandler: ["@mozilla.org/content/dropped-link-handler;1", "nsIDroppedLinkHandler"],
   els: ["@mozilla.org/eventlistenerservice;1", "nsIEventListenerService"],
   eTLD: ["@mozilla.org/network/effective-tld-service;1", "nsIEffectiveTLDService"],
+  idle: ["@mozilla.org/widget/idleservice;1", "nsIIdleService"],
   intl: ["@mozilla.org/mozintl;1", "mozIMozIntl"],
   locale: ["@mozilla.org/intl/localeservice;1", "mozILocaleService"],
   logins: ["@mozilla.org/login-manager;1", "nsILoginManager"],
   obs: ["@mozilla.org/observer-service;1", "nsIObserverService"],
   perms: ["@mozilla.org/permissionmanager;1", "nsIPermissionManager"],
   prompt: ["@mozilla.org/embedcomp/prompt-service;1", "nsIPromptService"],
   scriptloader: ["@mozilla.org/moz/jssubscript-loader;1", "mozIJSSubScriptLoader"],
   scriptSecurityManager: ["@mozilla.org/scriptsecuritymanager;1", "nsIScriptSecurityManager"],
--- a/toolkit/modules/tests/xpcshell/test_Services.js
+++ b/toolkit/modules/tests/xpcshell/test_Services.js
@@ -37,16 +37,17 @@ function run_test() {
   checkService("dirsvc", Ci.nsIDirectoryService);
   checkService("dirsvc", Ci.nsIProperties);
   checkService("DOMRequest", Ci.nsIDOMRequestService);
   checkService("domStorageManager", Ci.nsIDOMStorageManager);
   checkService("downloads", Ci.nsIDownloadManager);
   checkService("droppedLinkHandler", Ci.nsIDroppedLinkHandler);
   checkService("eTLD", Ci.nsIEffectiveTLDService);
   checkService("focus", Ci.nsIFocusManager);
+  checkService("idle", Ci.nsIIdleService);
   checkService("io", Ci.nsIIOService);
   checkService("io", Ci.nsIIOService2);
   checkService("intl", Ci.mozIMozIntl);
   checkService("locale", Ci.mozILocaleService);
   checkService("logins", Ci.nsILoginManager);
   checkService("obs", Ci.nsIObserverService);
   checkService("perms", Ci.nsIPermissionManager);
   checkService("prefs", Ci.nsIPrefBranch);