-
Notifications
You must be signed in to change notification settings - Fork 9.4k
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
DBW: add console.time -> performance.mark() suggestion #712
Conversation
- Also refactors common code into driver
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a couple of initial thoughts :)
prev.push(err); | ||
} | ||
return prev; | ||
}, []); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could also do something like
// Filter usage from other hosts.
const results = artifacts.ConsoleTimeUsage.usage.filter(err => {
return url.parse(err.url).host === pageHost;
}).map(err => `(line: ${err.line}, col: ${err.col})`);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
err.misc = `(line: ${err.line}, col: ${err.col})`; | ||
return err; | ||
}); | ||
}, []); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sames
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
beforePass(options) { | ||
const driver = options.driver; | ||
return driver.evaluateScriptOnLoad(` | ||
window.__consoleTimeStackTraces = new Set(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is still a bit fiddly on the caller's side.
Could more of this be pulled into driver? Maybe captureAPIUsage
could set up the collecting as it does here but also handles the evaluateScriptOnLoad
part and returns a collectUsage
function that could be called whenever (probably usually in afterPass
) that takes care of fetching the array of callsites for you? all without having to know that you're evaluating a script, that the callsites are on __consoleTimeStackTraces
in the host page, etc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But doesn't the evaluateScriptOnLoad
stuff need to be setup in beforePass? Or can that be pushed off until afterPass
time?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, I meant like, in beforePass
, have driver.captureAPIUsage().then(collectUsage => this.collectUsage = collectUsage)
and then in afterPass
have something like return this.collectUsage.then(uses => this.artifact = uses)
or whatever
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, exactly what I ended up doing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
PTAL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reviewed!
return url.parse(err.url).host === pageHost; | ||
}).map(err => { | ||
err.misc = `(line: ${err.line}, col: ${err.col})`; | ||
return err; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't mutate the errors in the artifact. Maybe
return Object.assign({
misc: `(line: ${err.line}, col: ${err.col})`
}, err);
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
// Filter usage from other hosts. | ||
const results = artifacts.DateNowUse.usage.filter(err => { | ||
return url.parse(err.url).host === pageHost; | ||
}).map(err => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
* on the global object. | ||
* @return {Function} A wrapper around the original function. | ||
*/ | ||
static captureUsage(func, set) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this should be in the Driver
class since it's not a method for it. One option would be to define it outside of the class body to make that clear?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
|
||
/** | ||
* Tracks function call usage. Used by captureJSCalls to inject code into the page. | ||
* @param {Function} func The function call to track. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could do {function(...*): *}
, I think
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
/** | ||
* Tracks function call usage. Used by captureJSCalls to inject code into the page. | ||
* @param {Function} func The function call to track. | ||
* @param {Set} set An empty set to populate with stack traces. Should be |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
{!Set}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
* Keeps track of calls to a JS function and returns a list of {url, line, col} | ||
* of the usage. | ||
* @param {string} funcVar The function name to track ('Date.now', 'console.time'). | ||
* @param {string} variableToPopulate The variable name to populate with stack traces. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
couldn't captureJSCalls
just generate the variable name? That prevents the gatherers from having to care the variables each other are using
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
aye. left a comment along those lines, too.
captureJSCalls(funcVar, variableToPopulate) { | ||
const collectUsage = () => { | ||
return this.evaluateAsync( | ||
`(__returnResults(Array.from(${variableToPopulate}).map(item => JSON.parse(item))))`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you need surrounding parens?
|
||
/** | ||
* Keeps track of calls to a JS function and returns a list of {url, line, col} | ||
* of the usage. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe a comment on usage? (must be called before page load, mostly)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
* @param {string} funcVar The function name to track ('Date.now', 'console.time'). | ||
* @param {string} variableToPopulate The variable name to populate with stack traces. | ||
* This should unique and on the global object ('window.__dateNowStackTraces'). | ||
* @return {Function} Call this method when you want results. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@return {function(): !Promise<!Array<{url: string, line: number, col: number}>>}
:)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@return {function(): !Promise<!Array<!{url: string, line: number, col: number}>>}
unless the contents of the array can be null also ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unless the contents of the array can be null also ;)
record types are non-nullable by default :P
|
||
afterPass() { | ||
return this.collectUsage().then(consoleTimeUsage => { | ||
this.artifact.usage = consoleTimeUsage; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do these have to saved on this.artifact.usage
? Could also just save on this.artifact
itself
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the consistency between audits of this natural. Always accessing the same .usage
array.
|
||
/** | ||
* Tracks function call usage. Used by captureJSCalls to inject code into the page. | ||
* @param {Function} func The function call to track. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
func
to funcRef
, just to be clearer it's not the string name of it anymore
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
what about |
`(__returnResults(Array.from(${variableToPopulate}).map(item => JSON.parse(item))))`); | ||
}; | ||
|
||
this.evaluateScriptOnLoad(` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm having a hard time parsing this magic. can we split it out a tad more?
I think this is basically what we're doing, eh?
this.evaluateScriptOnLoad(`
${variableToPopulate} = new Set();
function ${Driver.captureUsage.toString()};
${funcVar} = ${Driver.captureUsage.name}(${funcVar}, ${variableToPopulate});
`);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Slightly more important is renaming funcVar
to funcName
since it's in string form until the template literal is evaluated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
* This should unique and on the global object ('window.__dateNowStackTraces'). | ||
* @return {Function} Call this method when you want results. | ||
*/ | ||
captureJSCalls(funcVar, variableToPopulate) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Kind of prefer an options object for API here.. but what do you guys think?
driver.captureJSCalls({
funcName: 'console.time',
globalVarName: 'window.__consoleTimeStackTraces'
})
alternatively we can leave it alone because i can imagine we can later refactor out this second argument from the exposed API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
given there's only two args right now, I think it's fine.
this is definitely lgtm after this round. |
* @return {function(): !Promise<!Array<{url: string, line: number, col: number}>>} | ||
* Call this method when you want results. | ||
*/ | ||
captureFunctionCallSites(funcName, globalVarToPopulate) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not just, like, const globalVarToPopulate =
window['__${funcName}StackTraces']`` and then you'll get it for free and for most funcName
s you'll be sure no one else will be overwriting it :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yea that works
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
PTAL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. Great addition to driver
Boom. |
R: @brendankenny @paulirish @GoogleChrome/lighthouse
Usage is much simpler now to record API calls: