@atlaskit/editor-common
Version:
A package that contains common classes and components for editor and renderer
117 lines (115 loc) • 4.46 kB
JavaScript
import { isPerformanceAPIAvailable } from './is-performance-api-available';
/**
* Monitors if a pages enters a visibility state which will lead to
* distorted duration measurements (where the measurement uses the
* requestAnimationFrame api).
*/
export var getDistortedDurationMonitor = function getDistortedDurationMonitor() {
if (typeof document === 'undefined') {
return {
distortedDuration: false,
cleanup: function cleanup() {}
};
}
// If an editor is rendered when the document is not visible -- the callback passed to
// requestAnimationFrame will not fire until the document becomes visible again.
//
// For the purposes of using performance measurement -- this behaviour means the events
// which have been fired in the background are not useful -- and lead to other events
// being hard to draw conclusions from.
//
// To mitigate this -- we detect this state -- and fire a separate callback when the
// measurement has occurred when the render was in the background
var distortedDuration = document.visibilityState !== 'visible';
function handleVisibilityChange() {
if (document.visibilityState !== 'visible') {
distortedDuration = true;
}
}
// Ignored via go/ees005
// eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
document.addEventListener('visibilitychange', handleVisibilityChange);
return {
distortedDuration: distortedDuration,
/**
* Cleans up the document visibility event listener
*/
cleanup: function cleanup() {
// Ignored via go/ees005
// eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
document.removeEventListener('visibilitychange', handleVisibilityChange);
}
};
};
/**
* Measures time it takes to render a frame including -> style, paint, layout and composition.
*
* How does it work:
* 1. We mark the beginning of a render with the `startMark`
* 2. We schedule `requestAnimationFrame` callback for the next frame
* 3. Framework (e.g. prosemirror) does its magic and mounts dom nodes "synchronously"
* 4. When the main thread is unblocked our callback gets executed and onMeasureComplete is being called
*
* Why does it work:
* | javascript (framework) | style | layout | paint | composite | javascript | ...
* | startMark + scheduling rAF | | rAF callback, endMark
*/
export function measureRender(
/**
* Unique name for the measurement
*
* Important: if multiple measureRender events are fired at the same time
* with the same measure name -- the result will not be correct.
*/
measureName,
/**
* Call back fired when the measurement completes.
*
* Note: when this function is called when the Document.visibilityState is not
* visible -- the duration is likely to be misleading/inaccurate. This is due
* to the measurements use of the `requestAnimationFrame` api which only fires
* when the Document.visibilityState is visible.
*/
onMeasureComplete) {
if (!isPerformanceAPIAvailable()) {
return;
}
var startMark = "[START]: ".concat(measureName);
var endMark = "[END]: ".concat(measureName);
var startTime = performance.now();
performance.mark(startMark);
var distortedDurationMonitor = getDistortedDurationMonitor();
requestAnimationFrame(function () {
requestAnimationFrame(function () {
performance.mark(endMark);
distortedDurationMonitor.cleanup();
var duration = performance.now() - startTime;
try {
performance.measure(measureName, startMark, endMark);
var entry = performance.getEntriesByName(measureName).pop();
if (!entry) {
onMeasureComplete({
duration: duration,
startTime: startTime,
distortedDuration: distortedDurationMonitor.distortedDuration
});
} else {
onMeasureComplete({
duration: entry.duration,
startTime: entry.startTime,
distortedDuration: distortedDurationMonitor.distortedDuration
});
}
} catch (e) {
onMeasureComplete({
duration: duration,
startTime: startTime,
distortedDuration: distortedDurationMonitor.distortedDuration
});
}
performance.clearMeasures(measureName);
performance.clearMarks(startMark);
performance.clearMarks(endMark);
});
});
}