demo D100
Ten thousand updates a second
A trading-desk feed with the frame budget on screen
grid.updates.stats()
The configuration
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.13.0/lattice-grid.min.css">
<script src="https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.13.0/lattice-grid.min.js"></script>
<div id="grid" style="height: 540px"></div>
<script>
const grid = LatticeGrid.createGrid(document.getElementById('grid'), {
rowKey: 'id',
selection: 'multiple',
toolPanel: {
side: 'left',
panels: ['columns', 'filters', 'views', 'quick'],
actions: ['pause', 'undo', 'redo', 'export', 'maximise'],
exportName: 'lattice-demo',
},
statusBar: { panels: ['rowCount', 'progress', 'updates', 'selectedCount'] },
highlightOnChange: { duration: 400 },
// Queued changes land on a frame, which is what makes it one repaint per
// batch rather than one per message. budgetMs is the escape hatch: a flush
// that runs long hands the rest back and finishes next frame instead of
// dropping the frame it is in.
updates: { flush: 'frame', maxQueued: 20000, budgetMs: 8 },
columns: [
{ field: 'symbol', title: 'Symbol', layout: { width: 130, pin: 'start' } },
{ field: 'desk', title: 'Desk', filter: { type: 'set' } },
{ field: 'book', title: 'Book', filter: { type: 'set' } },
{ field: 'region', title: 'Region', filter: { type: 'set' } },
{ field: 'price', title: 'Price', type: 'number', layout: { width: 120 },
format: { decimals: 4 }, filter: { type: 'number' } },
{ field: 'change', title: 'Change', type: 'number', layout: { width: 110 },
format: { style: 'percent', decimals: 2 } },
{ field: 'volume', title: 'Volume', type: 'number', layout: { width: 120 },
format: { notation: 'compact' }, filter: { type: 'number' } },
{ field: 'ticks', title: 'Ticks', type: 'number', layout: { width: 90 } },
{ field: 'status', title: 'Status', filter: { type: 'set' }, layout: { width: 110 },
cell: { decoration: 'pill', variant: { map: { open: 'success', halted: 'danger', settled: 'neutral' } } } },
],
rows, // 20,000 instruments
});
// Push updates through the queue as they arrive from your feed. Each carries
// the key field; the grid coalesces and flushes them a frame at a time.
socket.onmessage = (event) => {
grid.rows.queue({ update: JSON.parse(event.data) });
};
</script>
Measuring throughput on a live-updating JavaScript data grid
A trading-desk feed does not arrive as a fresh dataset; it arrives as a stream of cell-level updates against rows already on screen, sometimes thousands per second, and a grid built for that has to keep rendering inside the frame budget rather than falling behind and buffering. A developer reaches for this when the source is a websocket or similar push feed with continuous partial updates, rather than the periodic full reloads a paged or remote source handles. Lattice Grid exposes grid.updates.stats() to read what is happening under load: updates received, updates applied, and the time spent per frame, so the cost of a given update rate is visible rather than inferred from a dropped frame count. Internally, updates are batched per animation frame and applied only to the cells whose values changed, so a feed touching a handful of columns across many rows does not force a re-render of the columns that did not move. This is the same batching that makes virtual scrolling viable at high row counts: only visible cells are ever painted, so update volume off-screen costs nothing until it scrolls into view. The demo puts the frame budget on the page itself, so the trade-off between update rate and render cost is something you watch happen rather than something you take on trust.
How many updates a second can a JavaScript data grid handle?
The ceiling depends on how many distinct cells change and how much of the grid is visible, not on total row count. Lattice Grid batches incoming updates per frame and repaints only the cells whose values changed, so ten thousand updates a second against a handful of visible columns stays within a 16ms frame budget; grid.updates.stats() reports the actual figures for a given feed and viewport rather than a fixed number.