![JAR search and dependency download from the Maven repository](/logo.png)
package.test.benchmark.core.ts Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of snabbdom Show documentation
Show all versions of snabbdom Show documentation
A virtual DOM library with focus on simplicity, modularity, powerful features and performance.
The newest version!
import "core-js/stable/array/fill.js";
import faker from "faker";
import { VNode, h, init as curInit } from "../../src/index";
import { init as refInit } from "latest-snabbdom-release/build/package/init";
import { assert } from "chai";
import pReduce from "p-reduce";
import pMapSeries from "p-map-series";
import { std, mean } from "mathjs";
const RUNS = 5;
const PATCHES_PER_RUN = 100;
const WARM_UP_RUNS = 1;
const REQUEST_ANIMATION_FRAME_EVERY_N_PATCHES = 1;
const BENCHMARK_TIMEOUT_MINUTES = 10;
const REQUIRED_PRECISION = 0.02;
/* eslint-disable @typescript-eslint/no-unused-vars */
declare global {
// eslint-disable-next-line @typescript-eslint/naming-convention
const __karma__: {
info(info: unknown): void;
};
}
/* eslint-enable @typescript-eslint/no-unused-vars */
const ALLOWED_REGRESSION = 0.03;
describe("core benchmark", () => {
it("does not regress", async function Benchmark() {
this.timeout(BENCHMARK_TIMEOUT_MINUTES * 1000 * 60);
faker.seed(0);
const inputs = Array(PATCHES_PER_RUN)
.fill(null)
.map(() => {
return new Array(faker.random.number(20)).fill(null).map(() => ({
name: faker.company.companyName(),
catchPhrase: faker.company.catchPhrase(),
suffix: faker.company.companySuffix(),
products: Array(faker.random.number(3))
.fill(null)
.map(() => ({
name: faker.commerce.productName(),
color: faker.commerce.color(),
price: faker.commerce.price() + faker.finance.currencySymbol(),
})),
founded: faker.date.past(),
}));
});
type Input = typeof inputs[0];
const view = (companies: Input): VNode =>
h("table", [
h("caption", ["Companies"]),
h("thead", [
h(
"tr",
["Details", "Products"].map((th) => h("th", [th]))
),
]),
h(
"tbody",
companies.map(function companyView(company) {
return h("tr", [
h("td", [
h("div", [
h("b", [company.name]),
company.suffix && `\xa0${company.suffix}`,
]),
h("div", h("i", [company.catchPhrase])),
h("td", [
h("dt", ["Founded"]),
h("dd", [company.founded.toLocaleDateString()]),
]),
]),
h("td", [
h(
"ul",
company.products.map(function productView(product) {
return h("li", [
h("dl", [
h("dt", ["Name"]),
h("dd", [product.name]),
h("dt", ["Color"]),
h("dd", [product.color]),
h("dt", ["Price"]),
h("dd", [product.price]),
]),
]);
})
),
]),
]);
})
),
]);
type Patcher = ReturnType;
interface SingleRunResult {
i: number;
cur: number;
ref: number;
}
const subjectToResult = async (
subject: Patcher,
subjectId: string
): Promise => {
await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
const markName = `mark:${subjectId}`;
const measureName = `measure:${subjectId}`;
performance.mark(markName);
const lastVnode = await pReduce(
inputs,
async function subjectToResultReducer(
acc: HTMLElement | VNode,
input,
i
) {
const vnode = view(input);
subject(acc, vnode);
if (i % REQUEST_ANIMATION_FRAME_EVERY_N_PATCHES === 0) {
await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
}
return vnode;
},
document.body.appendChild(document.createElement("section"))
);
performance.measure(measureName, markName);
if (!("elm" in lastVnode)) throw new Error();
if (!lastVnode.elm) throw new Error();
document.body.removeChild(lastVnode.elm);
const measure = performance.getEntriesByName(measureName)[0];
performance.clearMarks(markName);
performance.clearMeasures(measureName);
return measure.duration;
};
const singleRun = async (
_: null,
runI: number
): Promise => {
const cur = await subjectToResult(curInit([]), `cur:${runI}`);
const ref = await subjectToResult(refInit([]), `ref:${runI}`);
return { i: runI, cur, ref };
};
const runResults = (
await pMapSeries(Array(RUNS + WARM_UP_RUNS).fill(null), singleRun)
).slice(WARM_UP_RUNS);
__karma__.info({ benchmark: runResults });
const results = {
ref: runResults.map((result) => result.ref),
cur: runResults.map((result) => result.cur),
};
const means = {
ref: mean(results.ref),
cur: mean(results.cur),
};
const stds = {
ref: std(results.ref, "uncorrected"),
cur: std(results.cur, "uncorrected"),
};
(["ref", "cur"] as const).forEach((subject) => {
const stdRatio = stds[subject] / means[subject];
assert.isAtMost(
stdRatio,
REQUIRED_PRECISION,
`${subject} not precise enough`
);
});
assert.isAtMost(means.cur, means.ref * (1 + ALLOWED_REGRESSION));
});
});
© 2015 - 2025 Weber Informatics LLC | Privacy Policy