-
Notifications
You must be signed in to change notification settings - Fork 9.6k
core(image-elements): cap natural size fetch time #7274
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -87,8 +87,8 @@ function collectImageElementInfo() { | |
| displayedHeight: element.clientHeight, | ||
| clientRect: getClientRect(element), | ||
| // CSS Images do not expose natural size, we'll determine the size later | ||
| naturalWidth: Number.MAX_VALUE, | ||
| naturalHeight: Number.MAX_VALUE, | ||
| naturalWidth: 0, | ||
| naturalHeight: 0, | ||
| isCss: true, | ||
| isPicture: false, | ||
| usesObjectFit: false, | ||
|
|
@@ -130,12 +130,14 @@ class ImageElements extends Gatherer { | |
| async fetchElementWithSizeInformation(driver, element) { | ||
| const url = JSON.stringify(element.src); | ||
| try { | ||
| // We don't want this to take forever, 250ms should be enough for images that are cached | ||
| driver.setNextProtocolTimeout(250); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. one interesting aspect of our protocol timeouts is the effect of a bunch of orphaned protocol commands still running in the page. In this case there's also the
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correct loading the image to get the size info was taking a long time because it was reissuing the request. |
||
| /** @type {{naturalWidth: number, naturalHeight: number}} */ | ||
| const size = await driver.evaluateAsync(`(${determineNaturalSize.toString()})(${url})`); | ||
| return Object.assign(element, size); | ||
| } catch (_) { | ||
| // determineNaturalSize fails on invalid images, which we treat as non-visible | ||
| return Object.assign(element, {naturalWidth: 0, naturalHeight: 0}); | ||
| return element; | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -147,7 +149,9 @@ class ImageElements extends Gatherer { | |
| async afterPass(passContext, loadData) { | ||
| const driver = passContext.driver; | ||
| const indexedNetworkRecords = loadData.networkRecords.reduce((map, record) => { | ||
| if (/^image/.test(record.mimeType) && record.finished) { | ||
| // The network record is only valid for size information if it finished with a successful status | ||
| // code that indicates a complete resource response. | ||
| if (/^image/.test(record.mimeType) && record.finished && record.statusCode === 200) { | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is technically the only fix explicitly required for #7273, but seemed like a good idea to address other potential situations too |
||
| map[record.url] = record; | ||
| } | ||
|
|
||
|
|
@@ -163,6 +167,9 @@ class ImageElements extends Gatherer { | |
| const elements = await driver.evaluateAsync(expression); | ||
|
|
||
| const imageUsage = []; | ||
| const top50Images = Object.values(indexedNetworkRecords) | ||
| .sort((a, b) => b.resourceSize - a.resourceSize) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should this be using the
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO, no. That fallback is for making sure we don't miss the super rare case of an image being GZIPped in our final savings estimate but has negligible effect on whether it counts in the top 50. |
||
| .slice(0, 50); | ||
| for (let element of elements) { | ||
| // Pull some of our information directly off the network record. | ||
| const networkRecord = indexedNetworkRecords[element.src] || {}; | ||
|
|
@@ -177,8 +184,13 @@ class ImageElements extends Gatherer { | |
|
|
||
| // Images within `picture` behave strangely and natural size information isn't accurate, | ||
| // CSS images have no natural size information at all. Try to get the actual size if we can. | ||
| // Additional fetch is expensive; don't bother if we don't have a networkRecord for the image. | ||
| if ((element.isPicture || element.isCss) && networkRecord) { | ||
| // Additional fetch is expensive; don't bother if we don't have a networkRecord for the image, | ||
| // or it's not in the top 50 largest images. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe we should include in the docs for the artifact that picture or css images don't have size info if they aren't in the top 50 largest images?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sure |
||
| if ( | ||
| (element.isPicture || element.isCss) && | ||
| networkRecord && | ||
| top50Images.includes(networkRecord) | ||
| ) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. for the else case of this conditional, it seems like we need to zero out
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll just convert the default to be these since the goal is to set every image to |
||
| element = await this.fetchElementWithSizeInformation(driver, element); | ||
| } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.