AsyncResolutionBatcher
Defined in: packages/engine/src/engine/AsyncResolutionBatcher.ts:81
Micro-batches async resolution completions into a single DAG walk + re-evaluation pass.
When multiple promises resolve within the same event-loop tick (e.g., 3 currency rates: USD→GBP, USD→EUR, USD→JPY all return within 2ms), this batcher collapses them into ONE DAG walk and ONE re-execution pass instead of 3 separate ones.
Lifecycle:
- Engine calls
add()after eachresolveAsync()completes queueMicrotask()schedulesflush()for the end of the current tickflush()deduplicates queryKeys, walks DAG once for all resolved keys, topologically sorts affected lines, re-executes, and fires listener events
Perf: For N resolutions in a tick, reduces DAG walks from N to 1 and re-executions from N*avgAffected to totalAffected.
Streaming Architecture
Section titled “Streaming Architecture” * Events are published to a native ReadableStream. Stream-based- consumers read from the stream via
getReader(), gaining built-in - cancellation (
reader.cancel()), proper resource cleanup - (
reader.releaseLock()), and the ability to pipeTo()/pipeThrough()/tee()the event flow.
The stream uses a configurable CountQueuingStrategy with a default
highWaterMark of 64 events to limit the internal buffer size.
Constructors
Section titled “Constructors”Constructor
Section titled “Constructor”new AsyncResolutionBatcher( dag, lineCache, vm, highWaterMark?): AsyncResolutionBatcher;Defined in: packages/engine/src/engine/AsyncResolutionBatcher.ts:181
Parameters
Section titled “Parameters”| Parameter | Type | Default value |
|---|---|---|
dag | DependencyGraph | undefined |
lineCache | LineCache | undefined |
vm | VM | undefined |
highWaterMark | number | AsyncResolutionBatcher.DEFAULT_HIGH_WATER_MARK |
Returns
Section titled “Returns”AsyncResolutionBatcher
Properties
Section titled “Properties”_testCaptures
Section titled “_testCaptures”_testCaptures: | AsyncResolutionEvent[] | null = null;Defined in: packages/engine/src/engine/AsyncResolutionBatcher.ts:131
Test-only synchronous capture array. When enabled (non-null), every event is synchronously pushed here in addition to the stream. Tests read from this array to avoid async stream reader timing issues.
onLineResult
Section titled “onLineResult”onLineResult: ((lineNumber, value) => void) | null = null;Defined in: packages/engine/src/engine/AsyncResolutionBatcher.ts:149
Called for each line whose result is patched after an async resolution, on both the main-thread and worker-pool paths.
A host that displays async results must set this. It is the only mechanism that moves a resolved value out of the LineCache and into the host’s own document state. The engine cannot do it itself: it does not own a document, the host does, and the batcher has no reference to one.
Nullable rather than a constructor parameter because it is cleared by
clearAll() and re-wired on re-subscribe, so it cannot be readonly. That
makes it easy to miss, which is why warnIfUnwired exists: leaving
it unset means async values resolve into the cache and are never shown,
with nothing to indicate why. A host that genuinely does not want async
results should not register async resolvers at all.
Accessors
Section titled “Accessors”dedupCount
Section titled “dedupCount”Get Signature
Section titled “Get Signature”get dedupCount(): number;Defined in: packages/engine/src/engine/AsyncResolutionBatcher.ts:278
Number of pending entries collapsed by (packageId, queryKey) deduplication.
Returns
Section titled “Returns”number
listenerCount
Section titled “listenerCount”Get Signature
Section titled “Get Signature”get listenerCount(): number;Defined in: packages/engine/src/engine/AsyncResolutionBatcher.ts:291
Whether the internal event stream currently has an active reader.
1 if a consumer has called getEventStream().getReader() (or
otherwise locked the stream) and not released it, 0 otherwise.
Returns
Section titled “Returns”number
pendingCount
Section titled “pendingCount”Get Signature
Section titled “Get Signature”get pendingCount(): number;Defined in: packages/engine/src/engine/AsyncResolutionBatcher.ts:273
Number of resolutions currently queued for the next flush.
Returns
Section titled “Returns”number
workerOffloadCount
Section titled “workerOffloadCount”Get Signature
Section titled “Get Signature”get workerOffloadCount(): number;Defined in: packages/engine/src/engine/AsyncResolutionBatcher.ts:296
Number of flushes that were actually dispatched to the worker pool.
Returns
Section titled “Returns”number
Methods
Section titled “Methods”add(entry): void;Defined in: packages/engine/src/engine/AsyncResolutionBatcher.ts:220
Add a resolved query key to the pending batch.
Called by ExpressionEngine.resolveAsync() after a promise resolves or errors. If this is the first entry in the current tick, schedules a microtask flush.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
entry | BatchEntry |
Returns
Section titled “Returns”void
clearAll()
Section titled “clearAll()”clearAll(): void;Defined in: packages/engine/src/engine/AsyncResolutionBatcher.ts:301
Remove all listeners and cancel pending batch. Called on engine clear.
Returns
Section titled “Returns”void
getEventStream()
Section titled “getEventStream()”getEventStream(): ReadableStream<AsyncResolutionEvent>;Defined in: packages/engine/src/engine/AsyncResolutionBatcher.ts:268
Get the native event stream for stream-based consumers.
Use this for backpressure, cancellation, or the ability
to pipeTo() / pipeThrough() the event flow.
Returns
Section titled “Returns”ReadableStream<AsyncResolutionEvent>
A ReadableStream that emits AsyncResolutionEvent items as the batcher processes async resolutions.