LearnNewsExamplesServices
Frontmatter
id9332
titleCollection: Prevent deep cloning and spread operator limits when creating allItems
stateClosed
labels
bugaiperformance
assigneestobiu
createdAtFeb 27, 2026, 12:43 PM
updatedAtFeb 27, 2026, 12:54 PM
githubUrlhttps://github.com/neomjs/neo/issues/9332
authortobiu
commentsCount1
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtFeb 27, 2026, 12:54 PM

Collection: Prevent deep cloning and spread operator limits when creating allItems

Closed v12.0.0 bugaiperformance
tobiu
tobiu commented on Feb 27, 2026, 12:43 PM

When a Collection is filtered for the first time, it creates an allItems replica to store the unfiltered dataset:

me.allItems = me.createAllItems({
    // ...
    items: [...me._items],
    // ...
});

This causes two severe performance and memory issues for large datasets (e.g., 50k+ items in Turbo Mode):

  1. Spread Operator Limits: Spreading [...me._items] for massive arrays can hit browser engine limits (especially in Safari/Firefox) and cause stack overflows.
  2. Deep Cloning: Passing the massive items array directly into the config object causes Neo.core.Base to deeply clone all 50k items into this.originalConfig during instantiation. This takes multiple seconds and causes massive Garbage Collection pauses.

Fix: Create the allItems collection without the items config to completely bypass the originalConfig deep clone. Then, use me._items.slice() (which avoids spread operator limits while safely shallow-copying) and inject the items via me.allItems.add(), which natively handles internal chunking and stack-overflow protections.

tobiu added the bug label on Feb 27, 2026, 12:43 PM
tobiu added the ai label on Feb 27, 2026, 12:43 PM
tobiu added the performance label on Feb 27, 2026, 12:43 PM
tobiu referenced in commit 76b5ea8 - "perf(Collection): Prevent deep cloning and spread operator limits when creating allItems (#9332)" on Feb 27, 2026, 12:53 PM
tobiu assigned to @tobiu on Feb 27, 2026, 12:53 PM
tobiu
tobiu Feb 27, 2026, 12:53 PM

Input from Gemini 3.1 Pro:

✦ I have updated src/collection/Base.mjs to use me.allItems.items = me._items.slice();.

This bypasses the originalConfig deep clone, avoids the O(N^2) memory thrashing of Collection#splice doing repeated concats, and leverages the engine's highly optimized 2ms memcpy for .slice() without hitting any spread operator call stack limits.

Committed, pushed, and closing this ticket!

tobiu closed this issue on Feb 27, 2026, 12:54 PM