Files
orca/src/shared/event-loop-yield.ts
T
Neil 8b154d686c perf(runtime): remove timer clamps from cooperative yields (#10908)
* perf(runtime): remove timer clamps from cooperative yields

Renderer paste and input loops can schedule more than a thousand zero-delay timer yields for a maximum-size payload. Chromium clamps nested timers to 4ms, adding seconds of idle wall time.

Use MessageChannel tasks in renderer runtimes and setImmediate in Node while retaining a timer fallback for tests and unsupported environments.

* fix(runtime): preserve pacing and release yield callbacks

Adversarial review found that concurrent producers could retain resolved callbacks until global quiescence. Route renderer yields by token and delete each resolver before resuming its producer.

Keep timer pacing in terminal paste and accepted-write loops where SSH and local PTYs do not provide drain acknowledgement. Use the shared scheduler for the OpenCode scanner.
2026-07-27 12:21:14 -07:00

61 lines
1.8 KiB
TypeScript

type ImmediateGlobal = typeof globalThis & {
setImmediate?: (callback: () => void) => unknown
}
const pendingRendererYields = new Map<number, () => void>()
let nextRendererYieldId = 0
let rendererYieldChannel: MessageChannel | null = null
function isVitestEnvironment(): boolean {
return typeof process !== 'undefined' && process.env?.VITEST === 'true'
}
function getRendererYieldChannel(): MessageChannel {
if (!rendererYieldChannel) {
rendererYieldChannel = new globalThis.MessageChannel()
rendererYieldChannel.port1.onmessage = (event) => {
const yieldId = event.data
const resolve = typeof yieldId === 'number' ? pendingRendererYields.get(yieldId) : undefined
if (!resolve) {
return
}
pendingRendererYields.delete(yieldId)
resolve()
}
}
return rendererYieldChannel
}
/** @internal */
export function getPendingRendererYieldCountForTesting(): number {
return pendingRendererYields.size
}
/** Yields to another runnable task without a timer clamp when supported. */
export function yieldToEventLoop(): Promise<void> {
return new Promise((resolve) => {
// Vitest fake timers cannot advance MessageChannel tasks.
if (isVitestEnvironment()) {
globalThis.setTimeout(resolve, 0)
return
}
const setImmediate = (globalThis as ImmediateGlobal).setImmediate
if (typeof window === 'undefined' && setImmediate) {
setImmediate(resolve)
return
}
if (typeof globalThis.MessageChannel === 'function') {
// Posted tasks avoid Chromium's nested-timer clamp while still yielding to input and paint.
const yieldId = nextRendererYieldId
nextRendererYieldId += 1
pendingRendererYields.set(yieldId, resolve)
getRendererYieldChannel().port2.postMessage(yieldId)
return
}
globalThis.setTimeout(resolve, 0)
})
}