FEATURE: add Context#call_async and Context#eval_async - #441
Open
davidtaylorhq wants to merge 1 commit into
Open
FEATURE: add Context#call_async and Context#eval_async#441davidtaylorhq wants to merge 1 commit into
davidtaylorhq wants to merge 1 commit into
Conversation
These work like call and eval, except that when the result is a promise they block until it settles and return the settled value. A rejected promise raises MiniRacer::RuntimeError, like a synchronous throw, and non-promise results are returned as-is.
While waiting, the V8 thread alternates between draining the microtask queue and pumping the platform message loop in wait-for-work mode, so there is no polling: microtask chains settle immediately, and delayed or background work (Atomics.waitAsync timers, async wasm compilation) wakes the loop when its tasks are posted.
TerminateExecution doesn't wake a parked message loop, and when called while no JS is running it only queues a termination for the next JS entry. v8_terminate_execution therefore also sets a flag on the State and posts a no-op wakeup task, so the timeout watchdog, Context#stop and Ruby thread interrupts can all end a pending await. A promise that can never settle blocks like an infinite loop until one of those stops it.
The new methods use two new request opcodes ('D' and 'F') sharing the existing v8_call/v8_eval implementations. Ruby callbacks invoked while waiting go through the usual nested-dispatch path, and exceptions they raise propagate out through the promise rejection. TruffleRuby raises MiniRacer::Error.
davidtaylorhq
force-pushed
the
async-support
branch
from
August 10, 2026 18:50
38e3f0b to
d8322d2
Compare
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.
These work like call and eval, except that when the result is a promise they block until it settles and return the settled value. A rejected promise raises MiniRacer::RuntimeError, like a synchronous throw, and non-promise results are returned as-is.
While waiting, the V8 thread alternates between draining the microtask queue and pumping the platform message loop in wait-for-work mode, so there is no polling: microtask chains settle immediately, and delayed or background work (Atomics.waitAsync timers, async wasm compilation) wakes the loop when its tasks are posted.
TerminateExecution doesn't wake a parked message loop, and when called while no JS is running it only queues a termination for the next JS entry. v8_terminate_execution therefore also sets a flag on the State and posts a no-op wakeup task, so the timeout watchdog, Context#stop and Ruby thread interrupts can all end a pending await. A promise that can never settle blocks like an infinite loop until one of those stops it.
The new methods use two new request opcodes ('D' and 'F') sharing the existing v8_call/v8_eval implementations. Ruby callbacks invoked while waiting go through the usual nested-dispatch path, and exceptions they raise propagate out through the promise rejection. TruffleRuby raises MiniRacer::Error.