Commit 4fbba354 authored by estade@chromium.org's avatar estade@chromium.org

ntp: speed up startup by deferring app icon loads

This will defer the load of app icons on non-selected apps pages until that page is selected. Anecdotally this provides a noticeable speedup when 50ish apps are loaded.

I don't think this is really covered by any NTP startup test as it requires a lot of apps installed to have any effect. In lieu of creating such a test (which should be a TODO), I  tested locally the time to finish painting by inserting debug statements in NewTabUI::PaintTimeout(). I conducted these tests with the most visited page as the default. For browser startup, this patch reduced paint times from ~560 to ~460 ms on my setup (paint times were pretty consistent across runs). For just NTP startup (without another NTP already open), this patch reduced paint times from ~395 to ~295 ms (and these times were extremely consistent, never varying by more than 10ms from the mean). For reference, I also tested ntp3 and found the browser startup case to be about 570ms and NTP startup to be around 495ms (meaning NTP4 is a win with or without this patch, but especially with this patch).

BUG=none
TEST=manual

Review URL: http://codereview.chromium.org/7839013

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@99844 0039d316-1c4b-4281-b951-d872f2087c98
parent aae6965a
......@@ -189,8 +189,12 @@ cr.define('ntp4', function() {
this.useSmallIcon_ = true;
var appImg = this.ownerDocument.createElement('img');
// This is temporary (setIcon_/loadIcon will overwrite it) but is visible
// before the page is shown (e.g. if switching from most visited to
// bookmarks).
appImg.src = 'chrome://theme/IDR_APP_DEFAULT_ICON';
this.appImg_ = appImg;
this.setIcon();
this.setIcon_();
appImgContainer.appendChild(appImg);
if (this.useSmallIcon_) {
......@@ -266,16 +270,30 @@ cr.define('ntp4', function() {
},
/**
* Set the app's icon image from the appData.
* Set the URL of the icon from |appData_|. This won't actually show the
* icon until loadIcon() is called (for performance reasons; we don't want
* to load icons until we have to).
* @private
*/
setIcon: function() {
this.appImg_.src = this.useSmallIcon_ ? this.appData_.icon_small :
this.appData_.icon_big;
setIcon_: function() {
var src = this.useSmallIcon_ ? this.appData_.icon_small :
this.appData_.icon_big;
if (!this.appData_.enabled ||
(!this.appData_.offline_enabled && !navigator.onLine)) {
this.appImg_.src += '?grayscale=true';
src += '?grayscale=true';
}
this.appImgSrc_ = src;
},
/**
* Shows the icon for the app. That is, it causes chrome to load the app
* icon resource.
*/
loadIcon: function() {
if (this.appImgSrc_)
this.appImg_.src = this.appImgSrc_;
this.appImgSrc_ = null;
},
// Shows a notification text below the app icon and stuffs the attributes
......@@ -283,12 +301,8 @@ cr.define('ntp4', function() {
// text.
setupNotification_: function(notification) {
// Remove the old notification from this node (if any).
for (var i = 0; i < this.childNodes.length; i++) {
if (this.childNodes[i].classList.contains('app-notification')) {
this.removeChild(this.childNodes[i]);
break;
}
}
if (this.appNotification_)
this.appNotification_.parentNode.removeChild(this.appNotification_);
if (notification) {
// Add a new notification to this node.
......@@ -453,7 +467,8 @@ cr.define('ntp4', function() {
*/
replaceAppData: function(appData) {
this.appData_ = appData;
this.setIcon();
this.setIcon_();
this.loadIcon();
},
/**
......@@ -548,6 +563,8 @@ cr.define('ntp4', function() {
initialize: function() {
this.classList.add('apps-page');
this.addEventListener('cardselected', this.onCardSelected_);
},
/**
......@@ -566,6 +583,22 @@ cr.define('ntp4', function() {
this.appendTile(new App(appData), animate);
},
/**
* Handler for 'cardselected' event, fired when |this| is selected. The
* first time this is called, we load all the app icons.
* @private
*/
onCardSelected_: function(e) {
if (this.hasBeenSelected_)
return;
this.hasBeenSelected_ = true;
var apps = this.querySelectorAll('.app');
for (var i = 0; i < apps.length; i++) {
apps[i].loadIcon();
}
},
/** @inheritdoc */
doDragOver: function(e) {
var tile = ntp4.getCurrentlyDraggingTile();
......@@ -682,7 +715,6 @@ cr.define('ntp4', function() {
store.setAppsPromoData(data);
};
/**
* Callback invoked by chrome whenever an app preference changes.
* @param {Object} data An object with all the data on available
......
......@@ -298,6 +298,10 @@ var CardSlider = (function() {
event.initEvent(CardSlider.EventType.CARD_CHANGED, true, true);
event.cardSlider = this;
this.container_.dispatchEvent(event);
// We also dispatch an event on the card itself.
cr.dispatchSimpleEvent(this.currentCardValue, 'cardselected',
true, true);
}
},
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment