From JavaScript: @pond-ts/rs
@pond-ts/rs is pond-rs compiled to WebAssembly and called with pond-ts's
method names and argument shapes. Code written for pond-ts mostly runs as
is; the work happens in Rust, with the same answers as pond-ts, to the bit
(pond-ts's own test cases run through it in CI). It has pond-ts's version
number and is released with every pond-ts release.
npm install @pond-ts/rs
In Node
Node 20.19 or newer. Import it like any ES module (require works too,
as Node loads an ES module with require from 20.19); the WebAssembly is loaded
while the import runs, so there is nothing to wait for:
import { TimeSeries, Sequence, col } from '@pond-ts/rs';
const cpu = new TimeSeries({
name: 'cpu',
schema: [
{ name: 'time', kind: 'time' },
{ name: 'value', kind: 'number' },
],
rows: [
[0, 0.31],
[60_000, 0.44],
[120_000, 0.52],
],
});
const busy = cpu.filter(col('value').gt(0.4)); // runs inside pond-rs
const perTwoMinutes = cpu.aggregate(Sequence.every('2m'), { value: 'avg' });
console.log(busy.length, perTwoMinutes.toJSON().rows);
// 2 [ [ [ 0, 0, 120000 ], 0.375 ], [ [ 120000, 120000, 240000 ], 0.52 ] ]
for (const s of [busy, perTwoMinutes, cpu]) s.free();
In a browser
The same import works in a browser, with the same API. There the package
fetches and compiles its .wasm file with a top-level await, so the
import resolves once it is ready; nothing has to be called first. Which
loader runs is picked by the node export condition: bundlers building
for the browser take the browser one.
-
Vite: top-level
awaitneeds a 2022 target, and the package must not be pre-bundled (pre-bundling loses the.wasmfile):// vite.config.jsexport default {build: { target: 'es2022' },optimizeDeps: { exclude: ['@pond-ts/rs'] },};vite buildthen copies the.wasmfile intodist/assets. -
webpack 5, Parcel: they understand
new URL('./pkg/pond_wasm_bg.wasm', import.meta.url)and copy the file; webpack 5 has top-levelawaiton by default. Rollup needs a plugin for that, such as@web/rollup-plugin-import-meta-assets. -
esbuild: bundle with
--format=esm --target=es2022, then copynode_modules/@pond-ts/rs/pkg/pond_wasm_bg.wasmto<outdir>/pkg/(esbuild leaves thenew URLas is, so the file is looked for next to the bundle). -
No bundler: serve
node_modules/@pond-ts/rsand map two names in an import map,"@pond-ts/rs"to itsindex.jsand"#wasm"to itswasm.browser.js.
The .wasm file is about 7.5 MB, 1.4 MB with brotli (which most
servers and CDNs apply to it). Serve it as application/wasm so the
browser compiles it while it downloads.
Content Security Policy. Compiling WebAssembly needs
'wasm-unsafe-eval' in script-src. toJSON() writes its row loop
with new Function where that is allowed; under a policy without
'unsafe-eval' it uses a plain loop instead, with the same output, about
as fast as pond-ts's. Both are tested in headless Chromium, the second
under script-src 'self' 'wasm-unsafe-eval'.
TypeScript
The package ships no type declarations yet (they are planned). In
TypeScript under strict, importing it fails with TS7016 ("Could not find
a declaration file for module '@pond-ts/rs'"). Until types ship, declare
the module in a .d.ts file of your own, which types it as any:
declare module '@pond-ts/rs';
How it differs from pond-ts
The full list is in the package's README. The ones you meet first:
- Free what you make. A series lives in WebAssembly memory, which the
garbage collector cannot see. Call
free()when done with it. A finalizer frees forgotten series eventually, but WebAssembly memory never shrinks, so do not rely on it. Freeing aLiveSeriesfrees every view built on it. - Times are milliseconds. Rows take numbers for times; for times
written as text, use
Time.parseorTimeSeries.fromJSON. - Prefer expressions to functions.
s.filter(col('v').gt(0))runs inside pond-rs with no JavaScript call per row. A function works too, but each row then crosses into JavaScript and back, which is slower than pond-ts itself (1M rows: a filter with an expression about 11 ms, with a function about 620 ms; pond-ts 25 ms with the expression, 35 ms with the function). - Smaller event and time objects. Row lookups return
Events withget,data,key,begin,endandtimeRange, not the rest of pond-ts'sEventAPI. - One thread, and at most about 3.8 GB of memory per page or process.
- Error messages are pond-rs's, so the text differs from pond-ts's,
and the error is often a plain
Errorwhere pond-ts throws aTypeErrororRangeError.
Not included: @pond-ts/react, @pond-ts/charts and
@pond-ts/process; a series from @pond-ts/rs is not a pond-ts
TimeSeries, so pass data between them as JSON: toJSON() on one side,
TimeSeries.fromJSON on the other. (@pond-ts/rs also reads and writes
Arrow IPC bytes: TimeSeries.fromArrow, toArrow().)
Speed
Against pond-ts on one million rows, @pond-ts/rs is about 3–11× faster
for studies, 2.6–4.3× for toJSON, 2–3.5× for expressions and 1.4–5.5×
for live series, and much slower wherever a JavaScript function runs once
per row. The table is on Performance.