jsPerf.app is an online JavaScript performance benchmark test runner & jsperf.com mirror. It is a complete rewrite in homage to the once excellent jsperf.com now with hopefully a more modern & maintainable codebase.
jsperf.com URLs are mirrored at the same path, e.g:
https://jsperf.com/negative-modulo/2
Can be accessed at:
https://jsperf.app/negative-modulo/2
const stepsOrder1 = [
"read", // Read
"resolveKeyframes", // Write/Read/Write/Read
"update", // Compute
"preRender", // Compute
"render", // Write
"postRender", // Compute
]
const stepsOrder2 = [
"read", // Read
"resolveKeyframes", // Write/Read/Write/Read
"update", // Compute
"preRender", // Compute
"render", // Write
"postRender", // Compute
]
const stepsOrder3 = [
"read", // Read
"resolveKeyframes", // Write/Read/Write/Read
"update", // Compute
"preRender", // Compute
"render", // Write
"postRender", // Compute
]
const stepsOrderLength = stepsOrder3.length
const createRenderStep = () => {}
const scheduleNextBatch = () => {}
const allowKeepAlive = true
const result = [null]
function createRenderBatcher1(
scheduleNextBatch,
allowKeepAlive,
stepsOrder
) {
let runNextFrame = false
let useDefaultElapsed = true
const state = {
delta: 0,
timestamp: 0,
isProcessing: false,
}
const steps = stepsOrder.reduce((acc, key) => {
acc[key] = createRenderStep(() => (runNextFrame = true))
return acc
}, {})
const processStep = (stepId) => {
steps[stepId].process(state)
}
const processBatch = () => {
const timestamp = MotionGlobalConfig.useManualTiming
? state.timestamp
: performance.now()
runNextFrame = false
state.delta = useDefaultElapsed
? 1000 / 60
: Math.max(Math.min(timestamp - state.timestamp, maxElapsed), 1)
state.timestamp = timestamp
state.isProcessing = true
stepsOrder.forEach(processStep)
state.isProcessing = false
if (runNextFrame && allowKeepAlive) {
useDefaultElapsed = false
scheduleNextBatch(processBatch)
}
}
const wake = () => {
runNextFrame = true
useDefaultElapsed = true
if (!state.isProcessing) {
scheduleNextBatch(processBatch)
}
}
const schedule = stepsOrder.reduce((acc, key) => {
const step = steps[key]
acc[key] = (process, keepAlive = false, immediate = false) => {
if (!runNextFrame) wake()
return step.schedule(process, keepAlive, immediate)
}
return acc
}, {})
const cancel = (process) =>
stepsOrder.forEach((key) => steps[key].cancel(process))
return { schedule, cancel, state, steps }
}
function createRenderBatcher2(
scheduleNextBatch,
allowKeepAlive,
stepsOrder
) {
let runNextFrame = false
let useDefaultElapsed = true
const state = {
delta: 0,
timestamp: 0,
isProcessing: false,
}
const nextFrameFn = () => (runNextFrame = true)
const steps = {
read: createRenderStep(nextFrameFn),
resolveKeyframes: createRenderStep(nextFrameFn),
update: createRenderStep(nextFrameFn),
preRender: createRenderStep(nextFrameFn),
render: createRenderStep(nextFrameFn),
postRender: createRenderStep(nextFrameFn),
}
const processStep = (stepId) => {
steps[stepId].process(state)
}
const processBatch = () => {
const timestamp = MotionGlobalConfig.useManualTiming
? state.timestamp
: performance.now()
runNextFrame = false
state.delta = useDefaultElapsed
? 1000 / 60
: Math.max(Math.min(timestamp - state.timestamp, maxElapsed), 1)
state.timestamp = timestamp
state.isProcessing = true
for (let i = 0; i < stepsOrderLength; ++i) processStep(stepsOrder[i])
state.isProcessing = false
if (runNextFrame && allowKeepAlive) {
useDefaultElapsed = false
scheduleNextBatch(processBatch)
}
}
const wake = () => {
runNextFrame = true
useDefaultElapsed = true
if (!state.isProcessing) {
scheduleNextBatch(processBatch)
}
}
function batchFn(
process,
keepAlive = false,
immediate = false
) {
if (!runNextFrame) wake()
return this.schedule(process, keepAlive, immediate)
}
const schedule = {
read: batchFn.bind(steps.read),
resolveKeyframes: batchFn.bind(steps.resolveKeyframes),
update: batchFn.bind(steps.update),
preRender: batchFn.bind(steps.preRender),
render: batchFn.bind(steps.render),
postRender: batchFn.bind(steps.postRender),
}
const cancel = (process) => {
for (let i = 0; i < stepsOrderLength; ++i)
steps[stepsOrder[i]].cancel(process)
}
return { schedule, cancel, state, steps }
}
function createRenderBatcher3(
scheduleNextBatch,
allowKeepAlive,
stepsOrder
) {
let runNextFrame = false
let useDefaultElapsed = true
const state = {
delta: 0,
timestamp: 0,
isProcessing: false,
}
const steps = {
read: null,
resolveKeyframes: null,
update: null,
preRender: null,
render: null,
postRender: null,
}
const runNextFrameFn = () => (runNextFrame = true)
for (let i = 0; i < stepsOrderLength; ++i) {
const key = stepsOrder[i]
steps[key] = createRenderStep(runNextFrameFn)
}
const processStep = (stepId) => {
steps[stepId].process(state)
}
const processBatch = () => {
const timestamp = MotionGlobalConfig.useManualTiming
? state.timestamp
: performance.now()
runNextFrame = false
state.delta = useDefaultElapsed
? 1000 / 60
: Math.max(Math.min(timestamp - state.timestamp, maxElapsed), 1)
state.timestamp = timestamp
state.isProcessing = true
for (let i = 0; i < stepsOrderLength; ++i) processStep(stepsOrder[i])
state.isProcessing = false
if (runNextFrame && allowKeepAlive) {
useDefaultElapsed = false
scheduleNextBatch(processBatch)
}
}
const wake = () => {
runNextFrame = true
useDefaultElapsed = true
if (!state.isProcessing) {
scheduleNextBatch(processBatch)
}
}
const schedule= {
read: null,
resolveKeyframes: null,
update: null,
preRender: null,
render: null,
postRender: null,
}
for (let i = 0; i < stepsOrderLength; ++i) {
const key = stepsOrder[i]
const step = steps[key]
schedule[key] = (
process,
keepAlive = false,
immediate = false
) => {
if (!runNextFrame) wake()
return step.schedule(process, keepAlive, immediate)
}
}
const cancel = (process) => {
for (let i = 0; i < stepsOrderLength; ++i)
steps[stepsOrder[i]].cancel(process)
}
return { schedule, cancel, state, steps }
}
Ready to run.
Test | Ops/sec | |
---|---|---|
old |
| ready |
new (without for) |
| ready |
new(with for) |
| ready |
You can edit these tests or add more tests to this page by appending /edit to the URL.