Skip to content

Commit

Permalink
allow computed artifacts to request other computed artifacts (#2018)
Browse files Browse the repository at this point in the history
  • Loading branch information
brendankenny committed Apr 18, 2017
1 parent 32ab142 commit bbe7f3b
Show file tree
Hide file tree
Showing 11 changed files with 109 additions and 29 deletions.
2 changes: 2 additions & 0 deletions lighthouse-core/closure/typedefs/Artifacts.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@
*/

/**
* @constructor
* @struct
* @record
* @extends {ComputedArtifacts}
*/
function Artifacts() {}

Expand Down
60 changes: 60 additions & 0 deletions lighthouse-core/closure/typedefs/ComputedArtifacts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* 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.
*/

/**
* Typing externs file for computed artifacts object.
* @externs
*/

/** @typedef
{{
processEvents: !Array<!TraceEvent>,
startedInPageEvt: !TraceEvent,
navigationStartEvt: !TraceEvent,
firstPaintEvt: TraceEvent,
firstContentfulPaintEvt: TraceEvent,
firstMeaningfulPaintEvt: TraceEvent
}} */
let TraceOfTabArtifact;

/**
* @constructor
* @struct
* @record
*/
function ComputedArtifacts() {}

/** @type {function(!Array): !Promise<!Object>} */
ComputedArtifacts.prototype.requestCriticalRequestChains;

/** @type {function(ManifestNode<(!Manifest|undefined)>): !Promise<{isParseFailure: boolean, parseFailureReason: string, allChecks: !Array<{passing: boolean, failureText: string}>}>} */
ComputedArtifacts.prototype.requestManifestValues;

/** @type {function(!Array): !Promise<number>} */
ComputedArtifacts.prototype.requestNetworkThroughput;

// ComputedArtifacts.prototype.requestPushedRequests;

// ComputedArtifacts.prototype.requestScreenshots;

/** @type {function(!Trace): !Promise<!SpeedlineArtifact>} */
ComputedArtifacts.prototype.requestSpeedline;

/** @type {function(!Trace): !Promise<!TraceOfTabArtifact>} */
ComputedArtifacts.prototype.requestTraceOfTab;

/** @type {function(!Trace): !Promise<!tr.Model>} */
ComputedArtifacts.prototype.requestTracingModel;
3 changes: 3 additions & 0 deletions lighthouse-core/closure/typedefs/SpeedlineArtifact.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ function SpeedlineFrames() {}
/** @return {number} */
SpeedlineFrames.prototype.getProgress = function() {};

/** @return {number} */
SpeedlineFrames.prototype.getPerceptualProgress = function() {};

/** @return {number} */
SpeedlineFrames.prototype.getTimeStamp = function() {};

Expand Down
35 changes: 23 additions & 12 deletions lighthouse-core/gather/computed/computed-artifact.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,38 +18,49 @@
'use strict';

class ComputedArtifact {
constructor() {
this.cache = new Map();
/**
* @param {!ComputedArtifacts} allComputedArtifacts
*/
constructor(allComputedArtifacts) {
/** @private {!Map} */
this._cache = new Map();

/** @private {!ComputedArtifacts} */
this._allComputedArtifacts = allComputedArtifacts;
}

/* eslint-disable no-unused-vars */

/**
* Override to implement a computed artifact. Can return a Promise or the
* computed artifact itself.
* @param {!Object} artifact Input to computation.
* @param {*} artifact Input to computation.
* @param {!ComputedArtifacts} allComputedArtifacts Access to all computed artifacts.
* @return {*}
* @throws {Error}
*/
compute_(artifact) {
compute_(artifact, allComputedArtifacts) {
throw new Error('compute_() not implemented for computed artifact ' + this.name);
}

/* eslint-enable no-unused-vars */

/**
* Request a computed artifact, caching the result on the input artifact.
* @param {!OBject} artifact
* @return {!Promise}
* @param {*} artifact
* @return {!Promise<*>}
*/
request(artifact) {
if (this.cache.has(artifact)) {
return Promise.resolve(this.cache.get(artifact));
if (this._cache.has(artifact)) {
return Promise.resolve(this._cache.get(artifact));
}

return Promise.resolve().then(_ => this.compute_(artifact)).then(computedArtifact => {
this.cache.set(artifact, computedArtifact);
return computedArtifact;
});
return Promise.resolve()
.then(_ => this.compute_(artifact, this._allComputedArtifacts))
.then(computedArtifact => {
this._cache.set(artifact, computedArtifact);
return computedArtifact;
});
}
}

Expand Down
5 changes: 4 additions & 1 deletion lighthouse-core/gather/gather-runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -430,13 +430,16 @@ class GatherRunner {
}
}

/**
* @return {!ComputedArtifacts}
*/
static instantiateComputedArtifacts() {
const computedArtifacts = {};
require('fs').readdirSync(path.join(__dirname, 'computed')).forEach(function(file) {
// Drop `.js` suffix to keep browserify import happy.
file = file.replace(/\.js$/, '');
const ArtifactClass = require('./computed/' + file);
const artifact = new ArtifactClass();
const artifact = new ArtifactClass(computedArtifacts);
// define the request* function that will be exposed on `artifacts`
computedArtifacts['request' + artifact.name] = artifact.request.bind(artifact);
});
Expand Down
6 changes: 3 additions & 3 deletions lighthouse-core/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ class Runner {
run = run.then(_ => GatherRunner.run(config.passes, opts));
} else if (validArtifactsAndAudits) {
run = run.then(_ => {
return Object.assign(GatherRunner.instantiateComputedArtifacts(), config.artifacts);
return Object.assign(config.artifacts, GatherRunner.instantiateComputedArtifacts());
});
}

Expand Down Expand Up @@ -105,8 +105,8 @@ class Runner {
} else if (config.auditResults) {
// If there are existing audit results, surface those here.
// Instantiate and return artifacts for consistency.
const artifacts = Object.assign(GatherRunner.instantiateComputedArtifacts(),
config.artifacts || {});
const artifacts = Object.assign(config.artifacts || {},
GatherRunner.instantiateComputedArtifacts());
run = run.then(_ => {
return {
artifacts,
Expand Down
4 changes: 2 additions & 2 deletions lighthouse-core/test/audits/estimated-input-latency-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ const pwaTrace = require('../fixtures/traces/progressive-app.json');
const computedArtifacts = GatherRunner.instantiateComputedArtifacts();

function generateArtifactsWithTrace(trace) {
return Object.assign(computedArtifacts, {
return Object.assign({
traces: {
[Audit.DEFAULT_PASS]: trace
}
});
}, computedArtifacts);
}
/* eslint-env mocha */

Expand Down
4 changes: 2 additions & 2 deletions lighthouse-core/test/audits/first-meaningful-paint-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ const GatherRunner = require('../../gather/gather-runner.js');
const computedArtifacts = GatherRunner.instantiateComputedArtifacts();

function generateArtifactsWithTrace(trace) {
return Object.assign(computedArtifacts, {
return Object.assign({
traces: {
[Audit.DEFAULT_PASS]: {traceEvents: Array.isArray(trace) ? trace : trace.traceEvents}
}
});
}, computedArtifacts);
}

/* eslint-env mocha */
Expand Down
11 changes: 6 additions & 5 deletions lighthouse-core/test/audits/time-to-interactive-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,13 @@ const pwaTrace = require('../fixtures/traces/progressive-app.json');
/* eslint-env mocha */
describe('Performance: time-to-interactive audit', () => {
it('evaluates valid input correctly', () => {
const artifacts = GatherRunner.instantiateComputedArtifacts();
artifacts.traces = {
[TimeToInteractive.DEFAULT_PASS]: {
traceEvents: pwaTrace
const artifacts = Object.assign({
traces: {
[TimeToInteractive.DEFAULT_PASS]: {
traceEvents: pwaTrace
}
}
};
}, GatherRunner.instantiateComputedArtifacts());

return TimeToInteractive.audit(artifacts).then(output => {
assert.equal(output.rawValue, 1105.8, output.debugString);
Expand Down
4 changes: 2 additions & 2 deletions lighthouse-core/test/audits/user-timing-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ const GatherRunner = require('../../gather/gather-runner.js');
const computedArtifacts = GatherRunner.instantiateComputedArtifacts();

function generateArtifactsWithTrace(trace) {
return Object.assign(computedArtifacts, {
return Object.assign({
traces: {
[Audit.DEFAULT_PASS]: {traceEvents: Array.isArray(trace) ? trace : trace.traceEvents}
}
});
}, computedArtifacts);
}

/* eslint-env mocha */
Expand Down
4 changes: 2 additions & 2 deletions lighthouse-core/test/gather/computed/speedline-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ describe('Speedline gatherer', () => {
// on a MacBook Air, one run is 1000-1500ms
assert.ok(Date.now() - start < 50, 'Quick results come from the cache');

assert.ok(speedlineGather.cache.has(trace), 'Cache reports a match');
assert.equal(speedlineGather.cache.get(trace), speedline, 'Cache match matches');
assert.ok(speedlineGather._cache.has(trace), 'Cache reports a match');
assert.equal(speedlineGather._cache.get(trace), speedline, 'Cache match matches');

return assert.equal(Math.floor(speedline.speedIndex), 577);
});
Expand Down

0 comments on commit bbe7f3b

Please sign in to comment.