Last active
November 7, 2024 09:43
-
-
Save bvaughn/1fc166d5cb3f8c174a1552eeaeeaa0e6 to your computer and use it in GitHub Desktop.
Quick demonstration of a way to measure scrolling performance for react-virtualized in an automated way
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** Measures framerate for the time between start() and stop() calls */ | |
function FramerateMeasurer () { | |
this.start = () => { | |
this._beginTime = ( performance || Date ).now() | |
this._frames = 0 | |
this._animationFrameId = requestAnimationFrame(this._loop) | |
} | |
this.stop = () => { | |
const endTime = ( performance || Date ).now() | |
if (this._animationFrameId) { | |
cancelAnimationFrame(this._animationFrameId) | |
} | |
return { | |
beginTime: this._beginTime, | |
endTime, | |
framerate: (this._frames * 1000) / (endTime - this._beginTime), | |
frames: this._frames | |
} | |
} | |
this._loop = () => { | |
this._frames++ | |
this._animationFrameId = requestAnimationFrame(this._loop) | |
} | |
} | |
/** Runs an async test and measures its framerate until a confidence interface is achieved */ | |
function TestRunner (testCase, minSampleSize = 5) { | |
const framerateMeasurer = new FramerateMeasurer() | |
this.start = () => { | |
this._framerates = [] | |
this.isRunning = true | |
this._runTest() | |
} | |
this.stop = () => { | |
this.isRunning = false | |
console.log(`${this._framerates.length} framerate measurements taken, mean is: ${Statistics.calculateMean(this._framerates)}`) | |
} | |
this._getTestConfidence = () => { | |
if (this._framerates.length >= minSampleSize) { | |
const indices = this._framerates.map((framerate, index) => index) | |
const regressionSlope = Statistics.calculateRegressionSlope( | |
indices, | |
Statistics.calculateMean(indices), | |
this._framerates, | |
Statistics.calculateMean(this._framerates) | |
) | |
return regressionSlope >= 0 | |
} else { | |
return false | |
} | |
} | |
this._runTest = () => { | |
framerateMeasurer.start() | |
testCase(this._onTestComplete) | |
} | |
this._onTestComplete = () => { | |
if (!this.isRunning) { | |
return | |
} | |
const measurements = framerateMeasurer.stop() | |
console.log(`${measurements.frames} frames, framerate: ${measurements.framerate}`) | |
this._framerates.push(measurements.framerate) | |
const isConfident = this._getTestConfidence(this._framerates, minSampleSize) | |
if (isConfident) { | |
this.stop() | |
} else { | |
this._runTest() | |
} | |
} | |
} | |
// Adapted from https://github.com/angular/angular/modules/benchpress/src/statistic.ts | |
const Statistics = { | |
calculateMean: function (samples) { | |
const total = samples.reduce((total, x) => { | |
total += x | |
return total | |
}, 0) | |
return total / samples.length | |
}, | |
// See http://en.wikipedia.org/wiki/Simple_linear_regression | |
calculateRegressionSlope: function (xValues, xMean, yValues, yMean) { | |
let dividendSum = 0 | |
let divisorSum = 0 | |
for (var i = 0; i < xValues.length; i++) { | |
dividendSum += (xValues[i] - xMean) * (yValues[i] - yMean) | |
divisorSum += Math.pow(xValues[i] - xMean, 2) | |
} | |
return dividendSum / divisorSum | |
} | |
} | |
/** Tests a specific use case- scrolling a large FlexTable */ | |
function testCase (completedCallback) { | |
const flexTable = document.querySelector('.FlexTable__Grid') | |
flexTable.scrollTop = 0 | |
const maxScrollTop = flexTable.scrollHeight | |
let interval = 1 | |
let scrollTop = 0 | |
function incrementScrollTop () { | |
interval *= 1.1 | |
scrollTop = Math.min(scrollTop + interval, maxScrollTop) | |
flexTable.scrollTop = scrollTop | |
if (scrollTop < maxScrollTop) { | |
requestAnimationFrame(incrementScrollTop) | |
} else { | |
completedCallback() | |
} | |
} | |
incrementScrollTop() | |
} | |
const testRunner = new TestRunner(testCase) | |
document.body.addEventListener('click', | |
function () { | |
if (testRunner.isRunning) { | |
testRunner.stop() | |
} else { | |
testRunner.start() | |
} | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment