Skip to content

Commit fdeb746

Browse files
committed
docs: Enhance VDOM architecture documentation (#8841)
1 parent 5a94f54 commit fdeb746

4 files changed

Lines changed: 47 additions & 5 deletions

File tree

src/manager/VDomUpdate.mjs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ import Collection from '../collection/Base.mjs';
1515
* more focused data for the VDOM worker to process. While the amount of final DOM
1616
* modifications remains the same, this aggregation is key to performance.
1717
*
18+
* **Teleportation (Disjoint Updates):** The manager now supports processing multiple
19+
* disjoint components in a single "Teleportation" batch. This allows deep descendants
20+
* to update in parallel with their ancestors without requiring the ancestor to "bridge"
21+
* the gap, eliminating O(N) overhead for deep updates.
22+
*
1823
* 2. **Asynchronous Flow Control:** Manages the asynchronous nature of VDOM updates, which
1924
* are often processed in a worker thread. It ensures that code awaiting an update
2025
* (e.g., via a returned Promise) is correctly notified upon completion.
@@ -151,6 +156,13 @@ class VDomUpdate extends Collection {
151156
* Executes all callbacks associated with a completed VDOM update for a given `ownerId`.
152157
* This method first processes callbacks for any children that were merged into this
153158
* update cycle, then executes the callbacks for the `ownerId` itself.
159+
*
160+
* **Teleportation / Batch Support:**
161+
* The `processedChildIds` argument is crucial for Disjoint Updates. It ensures we only
162+
* execute callbacks for children that were *actually* included in the VDOM payload.
163+
* Children that were filtered out (e.g. due to collisions with a parent update) will
164+
* NOT have their callbacks executed here; they will be handled by the covering parent's callback.
165+
*
154166
* @param {String} ownerId The `id` of the component whose update has just completed.
155167
* @param {Object} [data] Optional data to pass to the callbacks.
156168
* @param {Set<String>|null} [processedChildIds] IDs of children actually included in this update.

src/mixin/VdomLifecycle.mjs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,21 @@ class VdomLifecycle extends Base {
190190
}
191191

192192
/**
193-
* Internal method to send update requests to the vdom worker
193+
* Internal method to send update requests to the vdom worker.
194+
*
195+
* **Teleportation / Batched Disjoint Updates:**
196+
* This method implements the core logic for "Teleportation". Instead of merging child updates
197+
* into the parent's VDOM tree (which requires expanding the parent's tree to reach the child),
198+
* we collect all merged child updates and send them as a **batch of disjoint payloads**.
199+
*
200+
* 1. **Recursive Collection:** We recursively collect all `mergedChildIds` from the component
201+
* and its descendants.
202+
* 2. **Disjoint Payloads:** For each component in the batch, we generate a "self-only" VDOM
203+
* payload (`updateDepth: 1`). This allows the VDOM engine to update the child directly
204+
* without needing the parent to "bridge" to it.
205+
* 3. **Collision Filtering:** We filter out child updates that are already covered by a
206+
* parent update in the same batch (e.g., if the parent is doing a full tree update).
207+
*
194208
* @param {function} [resolve] used by promiseUpdate()
195209
* @param {function} [reject] used by promiseUpdate()
196210
* @private
@@ -218,7 +232,7 @@ class VdomLifecycle extends Base {
218232
const component = Neo.getComponent(componentId);
219233
if (!component || component.isDestroyed) return;
220234

221-
// Skip unmounted components. They will be expanded by the Parent's TreeBuilder (Hybrid/Leapfrog)
235+
// Skip unmounted components. They will be expanded by the Parent's TreeBuilder
222236
// and handled via the Parent's resolveVdomUpdate -> syncVnodeTree.
223237
if (!component.vnode) return;
224238

@@ -599,8 +613,8 @@ class VdomLifecycle extends Base {
599613
*
600614
* **Recursive Traversal:**
601615
* This method recursively walks up the component tree (`distance + 1`). This enables
602-
* transitive merging (Grandchild -> Child -> Parent) and leapfrog merging (skipping
603-
* clean parents).
616+
* transitive merging (Grandchild -> Child -> Parent) and merging into ancestors even
617+
* if intermediate parents are not updating.
604618
*
605619
* @param {String} parentId=this.parentId
606620
* @param {Function} [resolve] gets passed by updateVdom()
@@ -820,7 +834,7 @@ class VdomLifecycle extends Base {
820834
// The manager will ensure it's called when the appropriate update cycle completes.
821835
resolve && VDomUpdate.addPromiseCallback(me.id, resolve);
822836

823-
// Attempt to merge into a parent's update cycle (Teleportation/Leapfrog).
837+
// Attempt to merge into a parent's update cycle.
824838
// We do this even if silent, to ensure we catch the bus if a parent is departing.
825839
if (me.mergeIntoParentUpdate(parentId)) {
826840
me.needsVdomUpdate = true;

src/vdom/Helper.mjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -779,6 +779,10 @@ class Helper extends Base {
779779

780780
/**
781781
* Processes a map of updates sequentially and aggregates the results.
782+
* This method is the core of the "Teleportation" / Disjoint Updates architecture.
783+
* Instead of building a single bridged VDOM tree, we process multiple components
784+
* as separate, disjoint updates in a single batch.
785+
*
782786
* @param {Object} data
783787
* @param {Object} data.updates A map of update config objects: {componentId: updateOpts}
784788
* @returns {Object} { deltas: Object[], vnodes: Object }

test/playwright/unit/vdom/RealWorldUpdates.spec.mjs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,18 @@ class TestChildContainer extends Container {
8989
}
9090
TestChildContainer = Neo.setupClass(TestChildContainer);
9191

92+
/**
93+
* @summary Verification tests for Batched Disjoint VDOM Updates ("Teleportation").
94+
*
95+
* These tests cover complex, real-world update scenarios to ensure the VDOM engine
96+
* correctly handles:
97+
* 1. **Disjoint Updates:** Parent and Child updating in parallel without "Bridge Path" interference.
98+
* 2. **Recursive Merging:** Grandchild merging into Parent's batch (skipping Child).
99+
* 3. **Ghost Updates:** Updates triggered by components that are being removed/detached in the same tick.
100+
* 4. **Structural Changes:** Inserts and removes within batched updates.
101+
*
102+
* This suite is the primary regression guard for the Teleportation architecture.
103+
*/
92104
test.describe('Neo.vdom.VdomRealWorldUpdates', () => {
93105
let parent, child, grandchild, testRun = 0;
94106

0 commit comments

Comments
 (0)