{
  "id": 18893541,
  "title": "Incremental Dependency-Graph Recalculation for 184 Excel Formulas in a Browser Web Worker",
  "url": "https://urgent.news/2026/11/08/incremental-dependency-graph-recalculation-for-184-excel-formulas-in",
  "topic": "tech",
  "section": "Tech",
  "published": "2026-11-08T08:13:38.000Z",
  "source": {
    "name": "Dev.to",
    "slug": "dev-to",
    "url": "https://dev.to/mincho_milev_c7753077d5af/incremental-dependency-graph-recalculation-for-184-excel-formulas-in-a-browser-web-worker-2e61"
  },
  "original_language": "en",
  "account": "Spreadsheets struggle to maintain smooth performance when implemented directly in JavaScript. Editing a single cell in a massive spreadsheet triggers reevaluation of every formula on the main thread, causing frame drops and frozen keyboard navigation. To address this issue, Arte Sheets— a browser-based spreadsheet supporting 184 Excel-compatible functions, dynamic arrays, Pivot Tables, and various file import/export formats— moved formula evaluation and file conversion into separate Web Workers. However, simply moving work off the main thread is not enough; the worker must still recompute all 10,000 formulas on every keystroke, leading to long queues of outdated worker messages.\n\nThe authors designed a hybrid incremental precedent-closure and dynamic-spill fallback engine to tackle this challenge within a mere 60 lines of worker coordination code. Problem 1: Textbook spreadsheet tutorials assume cell dependencies form a static Directed Acyclic Graph (DAG). However, real-world .xlsx workbooks break these static DAG assumptions in three ways: volatile and dynamic-reference functions, dynamic array spills, and structural mutations. These complexities make it challenging to handle OFFSET and FILTER spills inside an incremental single-cell walker, as they can introduce stale-cache bugs. Conversely, falling back to full recalculation for every workbook makes simple financial sheets feel sluggish.\n\nProblem 2: To efficiently split safe incremental edits from spill/volatile passes, the calculation worker classifies every formula cell during upsert using a fast regex check for volatile and dynamic-spill functions. These functions are tracked in an unsafe set alongside sheet spillOwners. When an edit message arrives from the UI coordinator, the worker decides in O(1) whether to execute a full topological pass or a targeted incremental closure. The nextLayout variable contains information about the current workbook state, and needsFullPass checks if a full recalculation is required based on various conditions like workbook reset, workbook ID changes, layout differences, and unsafe set size.\n\nProblem 3: For the common case where workbooks contain functions like SUM, XLOOKUP, INDEX/MATCH, SUMIFS, IFERROR, PMT, and standard arithmetic, needsFullPass remains false. Instead of evaluating dependents immediately as they are discovered (which risks reading half-updated intermediate cells in diamond dependencies), the authors first close the transitive dirty set across recorded range precedents before evaluation. This ensures that chains of dependent cells see fresh values. The code iterates through a list of range points, checking each dependent formula's range against recorded precedents. If a hit is found, the calculation process continues with updated values.",
  "summary": "Spreadsheet UIs fail a simple latency test when built naively in JavaScript: the moment a user edits cell B4 in a 25,000-cell .xlsx model, evaluating every formula on the main thread drops frames and freezes keyboard navigation. When building Arte Sheets —a local-first browser spreadsheet supporting 184 Excel-compatible functions , dynamic arrays, Pivot Tables, and .xlsx / .ods / .csv / .tsv…",
  "key_points": [
    "Arte Sheets moves formula evaluation and file conversion into separate Web Workers.",
    "Hybrid incremental engine tackles 184 Excel-compatible functions' complexities.",
    "NeedsFullPass algorithm decides between full recalculation and targeted incremental closure."
  ],
  "editors_take": null,
  "illustration": null,
  "coverage": {
    "outlets": 1,
    "also_reported_by": []
  },
  "ai_generated": true,
  "disclaimer": "Summaries, key points and the editor’s take are written by software from other outlets’ reporting and may contain errors — always check the linked original."
}