Batch initial connectedCallback renders into a single microtask flush#365
Draft
mattcosta7 with Copilot wants to merge 2 commits into
Draft
Batch initial connectedCallback renders into a single microtask flush#365mattcosta7 with Copilot wants to merge 2 commits into
mattcosta7 with Copilot wants to merge 2 commits into
Conversation
Move the initial update() call off the synchronous insertion critical path by coalescing the first render of newly-connected <relative-time> elements into a single microtask-flushed batch. - Add module-level pendingElements set and pendingFlush flag - Add async flushPending() that snapshots and clears the set before iterating, then calls update() on each element - connectedCallback enqueues the element and triggers one flush per batch instead of calling update() synchronously; if #updating is already set (attributeChangedCallback fired before connection) skip enqueuing - disconnectedCallback removes the element from pendingElements so detached elements are never updated - attributeChangedCallback skips scheduling a separate microtask when the element is already in pendingElements (the batch flush handles it) - Add 4 new tests for: single-element microtask render, multi-element batch, disconnect-before-flush safety, attribute-change coalescing
Copilot
AI
changed the title
[WIP] Optimize update call for relative time elements
Batch initial connectedCallback renders into a single microtask flush
Jul 20, 2026
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.
For N
<relative-time>elements inserted together,connectedCallbackwas callingupdate()synchronously per element — N ancestor-walking locale/timeZone/hourCycle resolutions, N Intl format passes, N shadow-DOM writes — all blocking layout at startup.Changes
src/relative-time-element.tspendingElements: Set<RelativeTimeElement>andasync flushPending()that snapshots + clears the set before iterating (safe against mid-flush connect/disconnect side-effects), then callsupdate()on each element after a singleawait Promise.resolve().connectedCallback: enqueues into the batch instead of callingupdate()synchronously. If#updatingis already set (anattributeChangedCallbackmicrotask is already in-flight for this element), skips enqueuing — that microtask handles the first render.disconnectedCallback: addspendingElements.delete(this)so elements removed before the flush are never updated.attributeChangedCallback: short-circuits withreturnifpendingElements.has(this)— defers to the pending batch flush rather than scheduling a redundant second microtask.The microtask resolves before paint, so rendered text,
title, dispatched events, and the accessibility tree are identical to the previous synchronous behavior.test/relative-time.jsFour new tests in a
connectedCallback microtask batchingsuite: single-element deferred render, multi-element batch, disconnect-before-flush safety, and attribute-change-after-connect coalescing.