Skip to content

Instantly share code, notes, and snippets.

@radum
Forked from l8on/monitoring-jank.coffee
Last active June 16, 2017 12:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save radum/e8aadc5b120160e7d42b12fba3fd6f3f to your computer and use it in GitHub Desktop.
Save radum/e8aadc5b120160e7d42b12fba3fd6f3f to your computer and use it in GitHub Desktop.
Monitoring Jank Example
// From here https://gist.github.com/l8on/7378d518a001a87adaf42a00fb7e50be#file-monitoring-jank-coffee
// https://fulcrum.lever.co/monitoring-jank-how-we-found-the-slowest-parts-of-our-ui-b6ffd7386896
var isModernBrowser, isNative, setupJankTracking;
// Simple function that uses a heuristic to tell if a function
// is native code. Luckily this isn't security related code.
isNative = function(fn) {
return /\{\s*\[native code\]\s*\}/.test("" + fn);
};
// An easy check to ensure we are on a modern browser
isModernBrowser = function() {
var ref;
return (
window.addEventListener &&
((ref = window.performance) != null ? ref.now : void 0) &&
isNative(window.requestAnimationFrame)
);
};
// Do nothing if this is not a modern browser
if (!isModernBrowser()) {
return;
}
// Wait for the application to finish loading before setting up jank tracking.
window.addEventListener("load", setupJankTracking);
setupJankTracking = function() {
var EXPECTED_RAF_DURATION,
JANK_THRESHOLD,
MAX_DEPTH,
generateQuerySelector,
jankState,
onAnimationFrame,
onEvent,
trackJank;
// Browsers call back to `requestAnimationFrame` 60 times per second
// under smooth rendering conditions.
EXPECTED_RAF_DURATION = 1000.0 / 60.0;
// Only report jank if it is over this threshold
JANK_THRESHOLD = {
A_REASONABLE_THRESHOLD_FOR_YOUR_APP: A_REASONABLE_THRESHOLD_FOR_YOUR_APP
};
// Create state in shared scope
jankState = {
event: null,
location: null,
timerStart: null
};
onEvent = function(event) {
var ref;
// Only track one event at a time.
if (jankState.event) {
return;
}
jankState.event = event;
jankState.location = window.location.href;
jankState.timerStart = (ref = window.performance) != null
? ref.now()
: void 0;
return window.requestAnimationFrame(onAnimationFrame);
};
onAnimationFrame = function() {
var jankAmount;
// This can be negative as the next frame is not always 16ms away.
jankAmount =
window.performance.now() -
jankState.timerStart -
EXPECTED_RAF_DURATION;
// Some amount of jank is OK and mostly unnoticeable.
// Limit tracking to the out of the ordinary
if (jankAmount > JANK_THRESHOLD) {
trackJank(jankAmount);
}
// Reset jankState so we capture the next event
jankState.event = null;
jankState.location = null;
return (jankState.timerStart = null);
};
trackJank = function(jankAmount) {
// Ideally, your tracking infrastructure queues things up for the
// next event loop and doesn't block rendering.
return window.monitoring.track({
jankAmount: jankAmount,
querySelector: generateQuerySelector(),
locationChanged: window.location.href !== jankState.location
});
};
MAX_DEPTH = {
A_REASONABLE_DEPTH_FOR_YOUR_APP: A_REASONABLE_DEPTH_FOR_YOUR_APP
};
generateQuerySelector = function() {
// Watch out for synthetic events that don't have a target!
var querySelector;
if (!jankState.event.target) {
return "";
}
// You can imagine what traverseUpDOMTree would look like ;)
querySelector = traverseUpDOMTree(MAX_DEPTH);
return querySelector;
};
// We use event capturing here (the third param) to set up jank
// monitoring before standard event handlers do their work.
// Also, we attach to the window so the event listeners are not
// destroyed on navigation.
window.addEventListener("click", onEvent, true);
return window.addEventListener("keydown", onEvent, true);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment