Skip to content

Commit

Permalink
Follow changes in Layout Instability API.
Browse files Browse the repository at this point in the history
 - Ignore layout shift that occurs within 500ms of user input
 - Create a separate PerformanceObserver to capture layout shift before
 the PerfomanceObserver is created
  • Loading branch information
ericandrewlewis committed Jul 19, 2019
1 parent 23f27c3 commit 5841683
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 37 deletions.
21 changes: 13 additions & 8 deletions src/service/performance-impl.js
Expand Up @@ -302,7 +302,11 @@ export class Performance {
} else if (entry.entryType === 'layoutJank') {
this.aggregateJankScore_ += entry.fraction;
} else if (entry.entryType === 'layout-shift') {
this.aggregateShiftScore_ += entry.value;
// Ignore layout shift that occurs within 500ms of user input, as it is
// likely in response to the user's action.
if (!entry.hadRecentInput) {
this.aggregateShiftScore_ += entry.value;
}
}
};

Expand Down Expand Up @@ -332,13 +336,14 @@ export class Performance {
}

if (this.supportsLayoutInstabilityAPI_) {
// Programmatically read once as currently PerformanceObserver does not
// report past entries as of Chrome 61.
// https://bugs.chromium.org/p/chromium/issues/detail?id=725567
this.win.performance
.getEntriesByType('layout-shift')
.forEach(processEntry);
entryTypesToObserve.push('layout-shift');
// Layout shift entries are not available from the Performance Timeline
// through `getEntriesByType`, so a separate PerformanceObserver is
// required for this metric.
const layoutInstabilityObserver = new this.win.PerformanceObserver(list => {
list.getEntries().forEach(processEntry);
this.flush();
});
layoutInstabilityObserver.observe({type: 'layout-shift', buffered: true});
}

if (entryTypesToObserve.length === 0) {
Expand Down
80 changes: 51 additions & 29 deletions test/unit/test-performance.js
Expand Up @@ -1310,18 +1310,20 @@ describes.realWin('PeformanceObserver metrics', {amp: true}, env => {
// Document should be initially visible.
expect(fakeWin.document.visibilityState).to.equal('visible');

// Fake layout-shift that occured before the Performance service is started.
fakeWin.performance.getEntriesByType
.withArgs('layout-shift')
.returns([
{entryType: 'layout-shift', value: 0.25},
{entryType: 'layout-shift', value: 0.3},
]);

const perf = getPerformance();
// visibilitychange/beforeunload listeners are now added.
perf.coreServicesAvailable();

// Fake layout-shift that occured before the Performance service is started.
performanceObserver.triggerCallback({
getEntries() {
return [
{entryType: 'layout-shift', value: 0.25, hadRecentInput: false},
{entryType: 'layout-shift', value: 0.3, hadRecentInput: false},
];
},
});

// The document has become hidden, e.g. via the user switching tabs.
toggleVisibility(fakeWin, false);
expect(perf.events_.length).to.equal(1);
Expand All @@ -1332,15 +1334,23 @@ describes.realWin('PeformanceObserver metrics', {amp: true}, env => {

// The user returns to the tab, and more layout shift occurs.
toggleVisibility(fakeWin, true);
const list = {
performanceObserver.triggerCallback({
getEntries() {
return [
{entryType: 'layout-shift', value: 1},
{entryType: 'layout-shift', value: 0.0001},
{entryType: 'layout-shift', value: 1, hadRecentInput: false},
{entryType: 'layout-shift', value: 0.0001, hadRecentInput: false},
];
},
};
performanceObserver.triggerCallback(list);
});

// User input occurs which triggers layout shift, which is ignored.
performanceObserver.triggerCallback({
getEntries() {
return [
{entryType: 'layout-shift', value: 0.3, hadRecentInput: true},
];
},
});

toggleVisibility(fakeWin, false);
expect(perf.events_.length).to.equal(2);
Expand All @@ -1351,7 +1361,13 @@ describes.realWin('PeformanceObserver metrics', {amp: true}, env => {

// Any more layout shift shouldn't be reported.
toggleVisibility(fakeWin, true);
performanceObserver.triggerCallback(list);
performanceObserver.triggerCallback({
getEntries() {
return [
{entryType: 'layout-shift', value: 2, hadRecentInput: false},
];
},
});

toggleVisibility(fakeWin, false);
expect(perf.events_.length).to.equal(2);
Expand All @@ -1365,18 +1381,20 @@ describes.realWin('PeformanceObserver metrics', {amp: true}, env => {
// Document should be initially visible.
expect(fakeWin.document.visibilityState).to.equal('visible');

// Fake layout-shift that occured before the Performance service is started.
fakeWin.performance.getEntriesByType
.withArgs('layout-shift')
.returns([
{entryType: 'layout-shift', value: 0.25},
{entryType: 'layout-shift', value: 0.3},
]);

const perf = getPerformance();
// visibilitychange/beforeunload listeners are now added.
perf.coreServicesAvailable();

// Fake layout-shift that occured before the Performance service is started.
performanceObserver.triggerCallback({
getEntries() {
return [
{entryType: 'layout-shift', value: 0.25, hadRecentInput: false},
{entryType: 'layout-shift', value: 0.3, hadRecentInput: false},
];
},
});

// The document has become hidden, e.g. via the user switching tabs.
// Note: Don't fire visibilitychange (not supported in this case).
fakeWin.document.visibilityState = 'hidden';
Expand All @@ -1395,15 +1413,19 @@ describes.realWin('PeformanceObserver metrics', {amp: true}, env => {
sandbox.stub(Services.platformFor(fakeWin), 'isChrome').returns(true);
sandbox.stub(Services.platformFor(fakeWin), 'isSafari').returns(false);

// Fake layout-shift that occured before the Performance service is started.
fakeWin.performance.getEntriesByType
.withArgs('layout-shift')
.returns([
{entryType: 'layout-shift', value: 0.25},
{entryType: 'layout-shift', value: 0.3},
]);
const perf = getPerformance();
perf.coreServicesAvailable();

// Fake layout-shift that occured before the Performance service is started.
performanceObserver.triggerCallback({
getEntries() {
return [
{entryType: 'layout-shift', value: 0.25, hadRecentInput: false},
{entryType: 'layout-shift', value: 0.3, hadRecentInput: false},
];
},
});

viewerVisibilityState = VisibilityState.INACTIVE;
perf.onViewerVisibilityChange_();

Expand Down

0 comments on commit 5841683

Please sign in to comment.