Investigate the possibility for a yielding hydration step - #5164
Draft
JoviDeCroock wants to merge 3 commits into
Draft
Investigate the possibility for a yielding hydration step#5164JoviDeCroock wants to merge 3 commits into
JoviDeCroock wants to merge 3 commits into
Conversation
Freshly mounting components during hydration now invoke options._yield right before rendering. Throwing a thenable from the hook suspends the component through the existing suspended-hydration machinery (MODE_SUSPENDED | MODE_HYDRATE + _excess) and forceUpdate() resumes the subtree in place, letting an opt-in scheduler slice the hydration walk into budgeted tasks. Also clear COMPONENT_DIRTY when a component suspends before its first render: the bit is set at instantiation and only cleared during render, so a pre-render suspension left it set and the resuming forceUpdate was swallowed by enqueueRender. Costs +10 B brotli on core (4392 -> 4402).
Core: context provided across slices, refs on resumed subtrees, shouldComponentUpdate bypass on resume, inline resume via parent re-render racing a pending slice, the realistic deadline+pump scheduler, and pinned-down single-DOM-root limitations (fragment-root node loss, null-root sibling duplication) together with a shape-learning scheduler policy that avoids both. Compat: slicing composes with real Suspense/lazy suspensions, and hooks components resumed in a slice run effects exactly once. The deadline scheduler tests encode an important finding: resumed components render unconditionally, so a scheduler must pump the resume queue one component per microtask with deadline checks in between -- force-updating the whole queue re-hydrates all flat siblings in a single long task.
The excess array rebuilt from _excess during a resume is owned solely by the resuming component, so any nodes its subtree did not adopt are SSR leftovers. Element frames already sweep those (diffElementNodes), but the component resume path never did, so a node claimed by a component that then rendered null stayed in the DOM forever next to the duplicate its deopted sibling created. This downgrades the null-root pitfall from permanent duplication to a transient duplicate with lost node identity, matching the severity of the fragment-root case. The sound fix for both remains span markers emitted by render-to-string for components whose output is not exactly one element. Costs +20 B brotli on core (4402 -> 4422, +30 B total for the feature).
📊 Tachometer Benchmark ResultsSummaryduration
usedJSHeapSize
Resultscreate10kduration
usedJSHeapSize
filter-listduration
usedJSHeapSize
hydrate1kduration
usedJSHeapSize
many-updatesduration
usedJSHeapSize
replace1kduration
usedJSHeapSize
run-warmup-0
run-warmup-1
run-warmup-2
run-warmup-3
run-warmup-4
run-final
text-updateduration
usedJSHeapSize
tododuration
usedJSHeapSize
update10th1kduration
usedJSHeapSize
|
|
Size Change: +34 B (+0.22%) Total Size: 15.8 kB 📦 View Changed
ℹ️ View Unchanged
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This would allow a self-serve kind of yield mechanism, an example can be seen below
Now my concern is that this is quite open-ended and the main thing this hook gives is the point of invocation as well as only invoking during hydration. Another thing that would warrant change if we introduce this is to enable yielding during updates i.e. if our render queue contains 5 items and the first takes up 30ms we should be able to pause and then resume the 4 next items.
This PR is very much tentative but wanted to show what I've been thinking about.