LearnNewsExamplesServices
Frontmatter
id9094
titleFeat: Batch Streaming & Progressive Rendering for Proxy Loader
stateClosed
labels
aiperformancecore
assigneestobiu
createdAtFeb 10, 2026, 8:16 PM
updatedAtFeb 10, 2026, 8:24 PM
githubUrlhttps://github.com/neomjs/neo/issues/9094
authortobiu
commentsCount1
parentIssue9089
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtFeb 10, 2026, 8:24 PM

Feat: Batch Streaming & Progressive Rendering for Proxy Loader

Closed v12.0.0 aiperformancecore
tobiu
tobiu commented on Feb 10, 2026, 8:16 PM

Feat: Batch Streaming & Progressive Rendering for Proxy Loader

Objective

Optimize the Neo.data.proxy.Stream and Neo.data.Store integration to solve the performance regression caused by single-record event firing. Implement chunked streaming and progressive UI updates.

Problem

The initial implementation fired a data event for every single record in the NDJSON stream. For 11k records, this caused massive overhead (11k events, 11k store updates, 11k microtasks), blocking the App Worker for ~10s.

Solution

  1. Batching (chunkSize): Update Stream.mjs to buffer parsed records and fire the data event only when chunkSize (e.g., 500) is reached.
  2. Progressive Rendering: Update Store.mjs to remove suspendEvents during the stream. Instead, listen for the chunked data events, add the chunk to the store, and fire a load event immediately. This allows the Grid to render the first chunk (~500 rows) almost instantly while the rest of the stream continues in the background.

Tasks

  • Add chunkSize config to Neo.data.proxy.Stream.
  • Implement buffering logic in Stream.read() to yield arrays of records.
  • Refactor Neo.data.Store.load() to support progressive loading (remove suspendEvents, fire intermediate load events).
  • Update Unit Tests (Stream.spec.mjs, StoreProxy.spec.mjs).

Expected Outcome

  • Time to First Byte (TTFB): Unchanged.
  • Time to First Render (TTFR): Drastically reduced (O(chunkSize) instead of O(Total)).
  • UX: User sees the grid populate immediately. Scrollbar grows as data streams in.
tobiu added the ai label on Feb 10, 2026, 8:16 PM
tobiu added the performance label on Feb 10, 2026, 8:16 PM
tobiu added the core label on Feb 10, 2026, 8:16 PM
tobiu added parent issue #9089 on Feb 10, 2026, 8:17 PM
tobiu referenced in commit b3039cd - "feat: Implement Batch Streaming & Progressive Rendering (#9094)" on Feb 10, 2026, 8:18 PM
tobiu
tobiu Feb 10, 2026, 8:18 PM

Input from Gemini 3 Pro:

✦ I have implemented the batching and progressive rendering optimizations.

Changes

  1. src/data/proxy/Stream.mjs: Added chunkSize: 500. The read loop now buffers records and fires the data event with an array of 500 items at a time.
  2. src/data/Store.mjs:
    • Removed suspendEvents during the proxy load.
    • Updated the onData handler to accept an array and add() it directly.
    • Set isLoading = false immediately after the first chunk arrives to unmask the grid.
    • Fires load event after every chunk with the updated total count, allowing the Grid to update its scrollbar and row count progressively.

Verification

  • Updated test/playwright/unit/data/proxy/Stream.spec.mjs to expect array payloads.
  • Updated test/playwright/unit/data/StoreProxy.spec.mjs to verify progressive loading behavior.
  • Tests passed.

This should resolve the 10s regression and provide immediate visual feedback.

tobiu assigned to @tobiu on Feb 10, 2026, 8:22 PM
tobiu closed this issue on Feb 10, 2026, 8:24 PM