Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
core(tsc): tighten traceOfTab timing types
Browse files Browse the repository at this point in the history
brendankenny committed Aug 22, 2018
1 parent 1bd8b5e commit 3d219f8
Showing 11 changed files with 106 additions and 63 deletions.
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@ const BaseNode = require('../../lib/dependency-graph/base-node');
const ByteEfficiencyAudit = require('./byte-efficiency-audit');
const UnusedCSS = require('./unused-css-rules');
const NetworkRequest = require('../../lib/network-request');
const LHError = require('../../lib/errors');

/** @typedef {import('../../lib/dependency-graph/simulator/simulator')} Simulator */
/** @typedef {import('../../lib/dependency-graph/base-node.js').Node} Node */
@@ -91,6 +92,9 @@ class RenderBlockingResources extends Audit {
const metricComputationData = {trace, devtoolsLog, simulator, settings: metricSettings};
// @ts-ignore - TODO(bckenny): allow optional `throttling` settings
const fcpSimulation = await artifacts.requestFirstContentfulPaint(metricComputationData);
if (!traceOfTab.timestamps.firstContentfulPaint) {
throw new LHError(LHError.errors.NO_FCP);
}
const fcpTsInMs = traceOfTab.timestamps.firstContentfulPaint / 1000;

const nodesByUrl = getNodesAndTimingByUrl(fcpSimulation.optimisticEstimate.nodeTimings);
24 changes: 12 additions & 12 deletions lighthouse-core/audits/metrics.js
Original file line number Diff line number Diff line change
@@ -115,18 +115,18 @@ class Metrics extends Audit {
* @property {number=} estimatedInputLatencyTs
* @property {number} observedNavigationStart
* @property {number} observedNavigationStartTs
* @property {number} observedFirstPaint
* @property {number} observedFirstPaintTs
* @property {number} observedFirstContentfulPaint
* @property {number} observedFirstContentfulPaintTs
* @property {number} observedFirstMeaningfulPaint
* @property {number} observedFirstMeaningfulPaintTs
* @property {number} observedTraceEnd
* @property {number} observedTraceEndTs
* @property {number} observedLoad
* @property {number} observedLoadTs
* @property {number} observedDomContentLoaded
* @property {number} observedDomContentLoadedTs
* @property {number=} observedFirstPaint
* @property {number=} observedFirstPaintTs
* @property {number=} observedFirstContentfulPaint
* @property {number=} observedFirstContentfulPaintTs
* @property {number=} observedFirstMeaningfulPaint
* @property {number=} observedFirstMeaningfulPaintTs
* @property {number=} observedTraceEnd
* @property {number=} observedTraceEndTs
* @property {number=} observedLoad
* @property {number=} observedLoadTs
* @property {number=} observedDomContentLoaded
* @property {number=} observedDomContentLoadedTs
* @property {number} observedFirstVisualChange
* @property {number} observedFirstVisualChangeTs
* @property {number} observedLastVisualChange
Original file line number Diff line number Diff line change
@@ -17,16 +17,17 @@ class FirstContentfulPaint extends MetricArtifact {
* @param {LH.Artifacts.MetricComputationData} data
* @return {Promise<LH.Artifacts.Metric>}
*/
computeObservedMetric(data) {
async computeObservedMetric(data) {
const {traceOfTab} = data;
if (!traceOfTab.timestamps.firstContentfulPaint) {
throw new LHError(LHError.errors.NO_FCP);
}

return Promise.resolve({
timing: traceOfTab.timings.firstContentfulPaint,
return {
// FCP established as existing, so cast
timing: /** @type {number} */ (traceOfTab.timings.firstContentfulPaint),
timestamp: traceOfTab.timestamps.firstContentfulPaint,
});
};
}
}

8 changes: 4 additions & 4 deletions lighthouse-core/gather/computed/metrics/first-cpu-idle.js
Original file line number Diff line number Diff line change
@@ -177,14 +177,14 @@ class FirstCPUIdle extends MetricArtifact {
const DCL = traceOfTab.timings.domContentLoaded;
const traceEnd = traceOfTab.timings.traceEnd;

if (traceEnd - FMP < MAX_QUIET_WINDOW_SIZE) {
throw new LHError(LHError.errors.FMP_TOO_LATE_FOR_FCPUI);
}

if (!FMP || !DCL) {
throw new LHError(FMP ? LHError.errors.NO_DCL : LHError.errors.NO_FMP);
}

if (traceEnd - FMP < MAX_QUIET_WINDOW_SIZE) {
throw new LHError(LHError.errors.FMP_TOO_LATE_FOR_FCPUI);
}

const longTasksAfterFMP = TracingProcessor.getMainThreadTopLevelEvents(traceOfTab, FMP)
.filter(evt => evt.duration >= LONG_TASK_THRESHOLD);
const firstInteractive = FirstCPUIdle.findQuietWindow(FMP, traceEnd, longTasksAfterFMP);
Original file line number Diff line number Diff line change
@@ -17,16 +17,17 @@ class FirstMeaningfulPaint extends MetricArtifact {
* @param {LH.Artifacts.MetricComputationData} data
* @return {Promise<LH.Artifacts.Metric>}
*/
computeObservedMetric(data) {
async computeObservedMetric(data) {
const {traceOfTab} = data;
if (!traceOfTab.timestamps.firstMeaningfulPaint) {
throw new LHError(LHError.errors.NO_FMP);
}

return Promise.resolve({
timing: traceOfTab.timings.firstMeaningfulPaint,
return {
// FMP established as existing, so cast
timing: /** @type {number} */ (traceOfTab.timings.firstMeaningfulPaint),
timestamp: traceOfTab.timestamps.firstMeaningfulPaint,
});
};
}
}

3 changes: 3 additions & 0 deletions lighthouse-core/gather/computed/metrics/interactive.js
Original file line number Diff line number Diff line change
@@ -90,6 +90,9 @@ class Interactive extends MetricArtifact {
* @return {{cpuQuietPeriod: TimePeriod, networkQuietPeriod: TimePeriod, cpuQuietPeriods: Array<TimePeriod>, networkQuietPeriods: Array<TimePeriod>}}
*/
static findOverlappingQuietPeriods(longTasks, networkRecords, traceOfTab) {
if (!traceOfTab.timestamps.firstContentfulPaint) {
throw new LHError(LHError.errors.NO_FCP);
}
const FcpTsInMs = traceOfTab.timestamps.firstContentfulPaint / 1000;

/** @type {function(TimePeriod):boolean} */
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@

const MetricArtifact = require('./lantern-metric');
const BaseNode = require('../../../lib/dependency-graph/base-node');
const LHError = require('../../../lib/errors');

/** @typedef {BaseNode.Node} Node */

@@ -33,6 +34,10 @@ class FirstContentfulPaint extends MetricArtifact {
*/
getOptimisticGraph(dependencyGraph, traceOfTab) {
const fcp = traceOfTab.timestamps.firstContentfulPaint;
if (!fcp) {
throw new LHError(LHError.errors.NO_FCP);
}

const blockingScriptUrls = MetricArtifact.getScriptUrls(dependencyGraph, node => {
return (
node.endTime <= fcp && node.hasRenderBlockingPriority() && node.initiatorType !== 'script'
@@ -58,6 +63,10 @@ class FirstContentfulPaint extends MetricArtifact {
*/
getPessimisticGraph(dependencyGraph, traceOfTab) {
const fcp = traceOfTab.timestamps.firstContentfulPaint;
if (!fcp) {
throw new LHError(LHError.errors.NO_FCP);
}

const blockingScriptUrls = MetricArtifact.getScriptUrls(dependencyGraph, node => {
return node.endTime <= fcp && node.hasRenderBlockingPriority();
});
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@

const MetricArtifact = require('./lantern-metric');
const BaseNode = require('../../../lib/dependency-graph/base-node');
const LHError = require('../../../lib/errors');

/** @typedef {BaseNode.Node} Node */

@@ -33,6 +34,10 @@ class FirstMeaningfulPaint extends MetricArtifact {
*/
getOptimisticGraph(dependencyGraph, traceOfTab) {
const fmp = traceOfTab.timestamps.firstMeaningfulPaint;
if (!fmp) {
throw new LHError(LHError.errors.NO_FMP);
}

const blockingScriptUrls = MetricArtifact.getScriptUrls(dependencyGraph, node => {
return (
node.endTime <= fmp && node.hasRenderBlockingPriority() && node.initiatorType !== 'script'
@@ -58,6 +63,10 @@ class FirstMeaningfulPaint extends MetricArtifact {
*/
getPessimisticGraph(dependencyGraph, traceOfTab) {
const fmp = traceOfTab.timestamps.firstMeaningfulPaint;
if (!fmp) {
throw new LHError(LHError.errors.NO_FMP);
}

const requiredScriptUrls = MetricArtifact.getScriptUrls(dependencyGraph, node => {
return node.endTime <= fmp && node.hasRenderBlockingPriority();
});
54 changes: 28 additions & 26 deletions lighthouse-core/gather/computed/trace-of-tab.js
Original file line number Diff line number Diff line change
@@ -22,11 +22,6 @@ const TracingProcessor = require('../../lib/traces/tracing-processor');
const LHError = require('../../lib/errors');
const Sentry = require('../../lib/sentry');

// Bring in web-inspector for side effect of adding [].stableSort
// See https://github.com/GoogleChrome/lighthouse/pull/2415
// eslint-disable-next-line no-unused-vars
const NetworkRequest = require('../../lib/network-request');

class TraceOfTab extends ComputedArtifact {
get name() {
return 'TraceOfTab';
@@ -133,34 +128,41 @@ class TraceOfTab extends ComputedArtifact {
const mainThreadEvents = processEvents
.filter(e => e.tid === startedInPageEvt.tid);

// traceEnd must exist since at least navigationStart event was verified as existing.
const traceEnd = trace.traceEvents.reduce((max, evt) => {
return max.ts > evt.ts ? max : evt;
});

const metrics = {
navigationStart,
firstPaint,
firstContentfulPaint,
firstMeaningfulPaint,
traceEnd: {ts: traceEnd.ts + (traceEnd.dur || 0)},
load,
domContentLoaded,
const fakeEndOfTraceEvt = {ts: traceEnd.ts + (traceEnd.dur || 0)};

/** @param {{ts: number}=} event */
const getTimestamp = (event) => event && event.ts;
/** @type {LH.Artifacts.TraceTimes} */
const timestamps = {
navigationStart: navigationStart.ts,
firstPaint: getTimestamp(firstPaint),
firstContentfulPaint: getTimestamp(firstContentfulPaint),
firstMeaningfulPaint: getTimestamp(firstMeaningfulPaint),
traceEnd: fakeEndOfTraceEvt.ts,
load: getTimestamp(load),
domContentLoaded: getTimestamp(domContentLoaded),
};

const timings = {};
const timestamps = {};

Object.keys(metrics).forEach(metric => {
timestamps[metric] = metrics[metric] && metrics[metric].ts;
timings[metric] = (timestamps[metric] - navigationStart.ts) / 1000;
});
/** @param {number=} ts */
const getTiming = (ts) => ts === undefined ? undefined : (ts - navigationStart.ts) / 1000;
/** @type {LH.Artifacts.TraceTimes} */
const timings = {
navigationStart: 0,
firstPaint: getTiming(timestamps.firstPaint),
firstContentfulPaint: getTiming(timestamps.firstContentfulPaint),
firstMeaningfulPaint: getTiming(timestamps.firstMeaningfulPaint),
traceEnd: (timestamps.traceEnd - navigationStart.ts) / 1000,
load: getTiming(timestamps.load),
domContentLoaded: getTiming(timestamps.domContentLoaded),
};

// @ts-ignore - TODO(bckenny): many of these are actually `|undefined`, but
// undefined case needs to be handled throughout codebase. See also note for
// LH.Artifacts.TraceOfTab.
return {
timings: /** @type {LH.Artifacts.TraceTimes} */ (timings),
timestamps: /** @type {LH.Artifacts.TraceTimes} */ (timestamps),
timings,
timestamps,
processEvents,
mainThreadEvents,
startedInPageEvt,
Original file line number Diff line number Diff line change
@@ -95,6 +95,7 @@ describe('FirstInteractive computed artifact:', () => {
computeObservedMetric({
timings: {
firstMeaningfulPaint: 3400,
domContentLoaded: 2000,
traceEnd: 4500,
},
timestamps: {
39 changes: 26 additions & 13 deletions typings/artifacts.d.ts
Original file line number Diff line number Diff line change
@@ -365,30 +365,43 @@ declare global {

export type Speedline = speedline.Output<'speedIndex'>;

// TODO(bckenny): all but navigationStart could actually be undefined.
export interface TraceTimes {
navigationStart: number;
firstPaint: number;
firstContentfulPaint: number;
firstMeaningfulPaint: number;
firstPaint?: number;
firstContentfulPaint?: number;
firstMeaningfulPaint?: number;
traceEnd: number;
load: number;
domContentLoaded: number;
load?: number;
domContentLoaded?: number;
}

// TODO(bckenny): events other than started and navStart could be undefined.
export interface TraceOfTab {
timings: TraceTimes;
/** The raw timestamps of key metric events, in microseconds. */
timestamps: TraceTimes;
/** The relative times from navigationStart to key metric events, in milliseconds. */
timings: TraceTimes;
/** The subset of trace events from the page's process, sorted by timestamp. */
processEvents: Array<TraceEvent>;
/** The subset of trace events from the page's main thread, sorted by timestamp. */
mainThreadEvents: Array<TraceEvent>;
/** The event marking the start of tracing in the target browser. */
startedInPageEvt: TraceEvent;
/** The trace event marking navigationStart. */
navigationStartEvt: TraceEvent;
firstPaintEvt: TraceEvent;
firstContentfulPaintEvt: TraceEvent;
firstMeaningfulPaintEvt: TraceEvent;
loadEvt: TraceEvent;
domContentLoadedEvt: TraceEvent;
/** The trace event marking firstPaint, if it was found. */
firstPaintEvt?: TraceEvent;
/** The trace event marking firstContentfulPaint, if it was found. */
firstContentfulPaintEvt?: TraceEvent;
/** The trace event marking firstMeaningfulPaint, if it was found. */
firstMeaningfulPaintEvt?: TraceEvent;
/** The trace event marking loadEventEnd, if it was found. */
loadEvt?: TraceEvent;
/** The trace event marking domContentLoadedEventEnd, if it was found. */
domContentLoadedEvt?: TraceEvent;
/**
* Whether the firstMeaningfulPaintEvt was the definitive event or a fallback to
* firstMeaningfulPaintCandidate events had to be attempted.
*/
fmpFellBack: boolean;
}
}

0 comments on commit 3d219f8

Please sign in to comment.