[IMP] owl-runtime: detect render loops instead of freezing#1969
Merged
Conversation
When a component updates reactive state that an ancestor reads during render (e.g. a child whose setup() calls a parent state setter), the parent re-renders, recreates the child, runs setup() again, and so on. The cycle is driven entirely by microtasks, so the rAF-based DOM commit never runs and the tab freezes silently with no error, which is very hard to debug. Track how many times a root fiber is re-rendered before being committed to the DOM (renderCount, bumped in makeRootFiber when an uncommitted fiber is recycled). A healthy render commits and discards its fiber, so a fresh one always starts at 0; only a self-retriggering loop ever makes the count climb without bound. Once it exceeds MAX_RENDER_ITERATIONS, Fiber.render() bails through handleError with a clear OwlError naming the looping component, halting the loop and tearing the app down. Same idea as React's "Maximum update depth exceeded" / Vue's "Maximum recursive updates", adapted to Owl's async fiber model. closes #1968
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.
When a component updates reactive state that an ancestor reads during render (e.g. a child whose setup() calls a parent state setter), the parent re-renders, recreates the child, runs setup() again, and so on. The cycle is driven entirely by microtasks, so the rAF-based DOM commit never runs and the tab freezes silently with no error, which is very hard to debug.
Track how many times a root fiber is re-rendered before being committed to the DOM (renderCount, bumped in makeRootFiber when an uncommitted fiber is recycled). A healthy render commits and discards its fiber, so a fresh one always starts at 0; only a self-retriggering loop ever makes the count climb without bound. Once it exceeds MAX_RENDER_ITERATIONS, Fiber.render() bails through handleError with a clear OwlError naming the looping component, halting the loop and tearing the app down. Same idea as React's "Maximum update depth exceeded" / Vue's "Maximum recursive updates", adapted to Owl's async fiber model.
closes #1968