Skip to content

Commit

Permalink
feat: add firstInteractive (#2013)
Browse files Browse the repository at this point in the history
  • Loading branch information
patrickhulce authored and brendankenny committed Apr 30, 2017
1 parent 9ccfd00 commit da8e097
Show file tree
Hide file tree
Showing 20 changed files with 422,412 additions and 89,375 deletions.
2 changes: 1 addition & 1 deletion lighthouse-cli/test/fixtures/byte-efficiency/tester.html
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,6 @@ <h2>Byte efficiency tester page</h2>
</script>

<!-- Ensure the page takes at least 7 seconds and we don't exit before the lazily loaded image -->
<script src="delay-complete.js?delay=7000"></script>
<script src="delay-complete.js?delay=7000" async></script>
</body>
</html>
6 changes: 3 additions & 3 deletions lighthouse-core/audits/byte-efficiency/offscreen-images.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
'use strict';

const ByteEfficiencyAudit = require('./byte-efficiency-audit');
const TTIAudit = require('../time-to-interactive');
const URL = require('../../lib/url-shim');

const ALLOWABLE_OFFSCREEN_X = 100;
Expand Down Expand Up @@ -102,6 +101,7 @@ class OffscreenImages extends ByteEfficiencyAudit {
static audit_(artifacts) {
const images = artifacts.ImageUsage;
const viewportDimensions = artifacts.ViewportDimensions;
const trace = artifacts.traces[ByteEfficiencyAudit.DEFAULT_PASS];

let debugString;
const resultsMap = images.reduce((results, image) => {
Expand All @@ -124,8 +124,8 @@ class OffscreenImages extends ByteEfficiencyAudit {
return results;
}, new Map());

return TTIAudit.audit(artifacts).then(ttiResult => {
const ttiTimestamp = ttiResult.extendedInfo.value.timestamps.timeToInteractive / 1000000;
return artifacts.requestFirstInteractive(trace).then(firstInteractive => {
const ttiTimestamp = firstInteractive.timestamp / 1000000;
const results = Array.from(resultsMap.values()).filter(item => {
const isWasteful = item.wastedBytes > IGNORE_THRESHOLD_IN_BYTES &&
item.wastedPercent > IGNORE_THRESHOLD_IN_PERCENT;
Expand Down
72 changes: 72 additions & 0 deletions lighthouse-core/audits/first-interactive.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/**
* @license
* Copyright 2017 Google Inc. All rights reserved.
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
*/

'use strict';

const Audit = require('./audit');
const TracingProcessor = require('../lib/traces/tracing-processor');
const Formatter = require('../report/formatter');

// Parameters (in ms) for log-normal CDF scoring. To see the curve:
// https://www.desmos.com/calculator/rjp0lbit8y
const SCORING_POINT_OF_DIMINISHING_RETURNS = 1700;
const SCORING_MEDIAN = 10000;

const distribution = TracingProcessor.getLogNormalDistribution(
SCORING_MEDIAN,
SCORING_POINT_OF_DIMINISHING_RETURNS
);

class FirstInteractiveMetric extends Audit {
/**
* @return {!AuditMeta}
*/
static get meta() {
return {
category: 'Performance',
name: 'first-interactive',
description: 'First Interactive (beta)',
helpText: 'The first point at which necessary scripts of the page have loaded ' +
'and the CPU is idle enough to handle most user input.',
scoringMode: Audit.SCORING_MODES.NUMERIC,
requiredArtifacts: ['traces']
};
}

/**
* Identify the time the page is "first interactive"
* @see https://docs.google.com/document/d/1GGiI9-7KeY3TPqS3YT271upUVimo-XiL5mwWorDUD4c/edit#
*
* @param {!Artifacts} artifacts
* @return {!Promise<!AuditResult>}
*/
static audit(artifacts) {
const trace = artifacts.traces[Audit.DEFAULT_PASS];
return artifacts.requestFirstInteractive(trace)
.then(firstInteractive => {
let score = 100 * distribution.computeComplementaryPercentile(firstInteractive.timeInMs);
// Clamp the score to 0 <= x <= 100.
score = Math.min(100, score);
score = Math.max(0, score);
score = Math.round(score);

const displayValue = Math.round(firstInteractive.timeInMs / 10) * 10;
return {
score,
rawValue: firstInteractive.timeInMs,
displayValue: `${displayValue.toLocaleString()}ms`,
extendedInfo: {
value: firstInteractive,
formatter: Formatter.SUPPORTED_FORMATS.NULL,
}
};
});
}
}

module.exports = FirstInteractiveMetric;
20 changes: 10 additions & 10 deletions lighthouse-core/audits/load-fast-enough-for-pwa.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,17 @@
/** @fileoverview
* This audit evaluates if a page's load performance is fast enough for it to be considered a PWA.
* We are doublechecking that the network requests were throttled (or slow on their own)
* Afterwards, we report if the TTI is less than 10 seconds.
* Afterwards, we report if the TTFI is less than 10 seconds.
*/

const Audit = require('./audit');
const TTIMetric = require('./time-to-interactive');
const Emulation = require('../lib/emulation');

const Formatter = require('../report/formatter');

// Maximum TTI to be considered "fast" for PWA baseline checklist
// Maximum TTFI to be considered "fast" for PWA baseline checklist
// https://developers.google.com/web/progressive-web-apps/checklist
const MAXIMUM_TTI = 10 * 1000;
const MAXIMUM_TTFI = 10 * 1000;

class LoadFastEnough4Pwa extends Audit {
/**
Expand Down Expand Up @@ -63,20 +62,21 @@ class LoadFastEnough4Pwa extends Audit {
const areLatenciesAll3G = allRequestLatencies.every(val =>
val === undefined || val > latency3gMin);

return TTIMetric.audit(artifacts).then(ttiResult => {
const timeToInteractive = ttiResult.extendedInfo.value.timings.timeToInteractive;
const isFast = timeToInteractive < MAXIMUM_TTI;
const trace = artifacts.traces[Audit.DEFAULT_PASS];
return artifacts.requestFirstInteractive(trace).then(firstInteractive => {
const timeToFirstInteractive = firstInteractive.timeInMs;
const isFast = timeToFirstInteractive < MAXIMUM_TTFI;

const extendedInfo = {
formatter: Formatter.SUPPORTED_FORMATS.NULL,
value: {areLatenciesAll3G, allRequestLatencies, isFast, timeToInteractive}
value: {areLatenciesAll3G, allRequestLatencies, isFast, timeToFirstInteractive}
};

if (!areLatenciesAll3G) {
return {
rawValue: false,
// eslint-disable-next-line max-len
debugString: `The Time To Interactive was found at ${ttiResult.displayValue}, however, the network request latencies were not sufficiently realistic, so the performance measurements cannot be trusted.`,
debugString: `First Interactive was found at ${timeToFirstInteractive.toLocaleString()}, however, the network request latencies were not sufficiently realistic, so the performance measurements cannot be trusted.`,
extendedInfo
};
}
Expand All @@ -85,7 +85,7 @@ class LoadFastEnough4Pwa extends Audit {
return {
rawValue: false,
// eslint-disable-next-line max-len
debugString: `Under 3G conditions, the Time To Interactive was at ${ttiResult.displayValue}. More details in the "Performance" section.`,
debugString: `Under 3G conditions, First Interactive was at ${timeToFirstInteractive.toLocaleString()}. More details in the "Performance" section.`,
extendedInfo
};
}
Expand Down
3 changes: 3 additions & 0 deletions lighthouse-core/closure/typedefs/ComputedArtifacts.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,6 @@ ComputedArtifacts.prototype.requestTraceOfTab;

/** @type {function(!Trace): !Promise<!tr.Model>} */
ComputedArtifacts.prototype.requestTracingModel;

/** @type {function(!Trace): !Promise<{timeInMs: number, timestamp: number}>} */
ComputedArtifacts.prototype.requestFirstInteractive;
2 changes: 2 additions & 0 deletions lighthouse-core/config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ module.exports = {
"load-fast-enough-for-pwa",
"speed-index-metric",
"estimated-input-latency",
"first-interactive",
"time-to-interactive",
"user-timings",
"critical-request-chains",
Expand Down Expand Up @@ -616,6 +617,7 @@ module.exports = {
{"id": "speed-index-metric", "weight": 1},
{"id": "estimated-input-latency", "weight": 1},
{"id": "time-to-interactive", "weight": 5},
{"id": "first-interactive", "weight": 5},
{"id": "link-blocking-first-paint", "weight": 0},
{"id": "script-blocking-first-paint", "weight": 0},
// {"id": "unused-css-rules", "weight": 0},
Expand Down
Loading

0 comments on commit da8e097

Please sign in to comment.