Deferred Updates Queue Flush Timing Relative to Synchronous DOM Reads
0 reputation · 02 Dec 2021, 06:37 UTC
0 reputation · 02 Dec 2021, 06:37 UTC
When ko.options.deferUpdates is enabled, Knockout coalesces observable notifications into an internal task queue. The objective is to establish whether a synchronous DOM read immediately after an observable mutation observes the state before or after the queue flushes.
The documentation does not define a strict ordering guarantee between deferred notification processing and synchronous DOM reads or writes. The internal scheduler is not part of the public API, so application code cannot force an early flush, and behavior for computed observables without active subscribers may vary by Knockout version.
Is the deferred queue guaranteed to flush before the next synchronous DOM access? Does a subscriber-less computed re-evaluate during the deferred flush, or only when a new subscriber attaches?
35775 reputation · 02 Dec 2021, 08:15 UTC
No, the deferred updates queue is not guaranteed to flush before the next synchronous DOM access. When ko.options.deferUpdates = true, observable notifications are coalesced and flushed asynchronously via setTimeout in Knockout < 3.4 and requestAnimationFrame in 3.4+. A synchronous DOM read immediately after mutating an observable will observe the pre-flush (stale) state.
Subscriber-less computed observables do not re-evaluate during the deferred flush. They use lazy evaluation: the evaluator runs only when a new subscriber attaches (e.g., via subscribe() or a binding) or when the computed is explicitly accessed (e.g., computed.peek() or computed()). If a computed has at least one active subscriber, it will re-evaluate during the deferred flush as part of the normal dependency cascade.
Knockout's deferred updates implement a micro-batching strategy. When an observable is written, it marks itself dirty and schedules a single flush task. The flush task processes all dirty observables, notifies their subscribers, and triggers computed re-evaluation for those with active subscriptions. Because the flush is scheduled as a macrotask/animation-frame callback, any synchronous code that runs after the mutation, including DOM reads, executes before the flush.
Which Knockout version are you targeting? The flush mechanism (setTimeout vs requestAnimationFrame) and the exact timing of subscriber-less computed evaluation can differ between 3.x and 4.x, so the version determines whether a setTimeout(fn, 0) test reliably captures the flush.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.