From d32c6f6ce2776e1f0ed1dfda018dda1674b9910f Mon Sep 17 00:00:00 2001 From: agape1225 <49804691+agape1225@users.noreply.github.com> Date: Wed, 30 Sep 2026 18:46:31 +0900 Subject: [PATCH 1/2] vm: allow sharing a microtask queue across contexts Add `vm.createMicrotaskQueue()` and extend the `microtaskMode` option to accept `{ type: 'manual', queue }`, so multiple vm contexts can share a single, explicitly-drained microtask queue instead of each having its own privately auto-drained one. This lets embedders (e.g. implementing a Window/iframe pair) reproduce the spec's same-microtask-queue ordering guarantees, which was not previously possible from the public API. `'afterEvaluate'` and `{ type: 'manual', queue }` are mutually exclusive by construction, since they are two different values of the same option. Refs: https://github.com/nodejs/node/issues/65555 Signed-off-by: agape1225 <49804691+agape1225@users.noreply.github.com> --- doc/api/vm.md | 103 ++++++++- lib/vm.js | 59 ++++- src/env_properties.h | 1 + src/node_contextify.cc | 78 ++++++- src/node_contextify.h | 43 ++++ .../test-vm-shared-microtask-queue-gc.js | 30 +++ ...st-vm-shared-microtask-queue-validation.js | 63 +++++ .../test-vm-shared-microtask-queue.js | 215 ++++++++++++++++++ 8 files changed, 568 insertions(+), 24 deletions(-) create mode 100644 test/parallel/test-vm-shared-microtask-queue-gc.js create mode 100644 test/parallel/test-vm-shared-microtask-queue-validation.js create mode 100644 test/parallel/test-vm-shared-microtask-queue.js diff --git a/doc/api/vm.md b/doc/api/vm.md index 14cd1f269b12..acb2bb07814a 100644 --- a/doc/api/vm.md +++ b/doc/api/vm.md @@ -313,10 +313,18 @@ changes: `EvalError`. **Default:** `true`. * `wasm` {boolean} If set to false any attempt to compile a WebAssembly module will throw a `WebAssembly.CompileError`. **Default:** `true`. - * `microtaskMode` {string} If set to `afterEvaluate`, microtasks (tasks - scheduled through `Promise`s and `async function`s) will be run immediately - after the script has run. They are included in the `timeout` and - `breakOnSigint` scopes in that case. + * `microtaskMode` {string|Object} + * If set to the string `'afterEvaluate'`, microtasks (tasks + scheduled through `Promise`s and `async function`s) will be run + immediately after the script has run. They are included in the + `timeout` and `breakOnSigint` scopes in that case. + * If set to an object of the form `{ type: 'manual', queue }`, where + `queue` is a [`vm.MicrotaskQueue`][] created via + [`vm.createMicrotaskQueue()`][], microtasks scheduled while running the + script are placed on `queue` instead of being drained automatically. + `queue` may be shared with other contexts so that microtasks from all + of them can be drained together, in the order they were scheduled, via + a single explicit [`microtaskQueue.runMicrotasks()`][] call. * Returns: {any} the result of the very last statement executed in the script. This method is a shortcut to `script.runInContext(vm.createContext(options), options)`. @@ -1318,6 +1326,35 @@ added: A `ModuleRequest` represents the request to import a module with given import attributes and phase. +## Class: `vm.MicrotaskQueue` + + + +> Stability: 1 - Experimental + +An explicit microtask queue that can be attached to multiple contexts (via +the `microtaskMode` option of [`vm.createContext()`][], +[`vm.runInNewContext()`][], and [`script.runInNewContext()`][]) so that they +share where their microtasks (`Promise` reactions and `async function` +continuations) are placed, and so that those microtasks are drained together, +explicitly, by the embedder, instead of automatically by Node.js. + +Instances are created with [`vm.createMicrotaskQueue()`][]; there is no +public constructor. + +### `microtaskQueue.runMicrotasks()` + + + +Synchronously runs every microtask currently queued on `microtaskQueue`, in +the order in which they were scheduled. If running a microtask schedules +further microtasks on the same queue, those are run as well before this +method returns. + ## `vm.compileFunction(code[, params[, options]])` + +* Returns: {vm.MicrotaskQueue} + +Creates a new [`vm.MicrotaskQueue`][] that can be passed as the `queue` of a +`{ type: 'manual', queue }` value for the `microtaskMode` option of +[`vm.createContext()`][], so that multiple contexts can share where their +microtasks are placed. See [`vm.MicrotaskQueue`][] for details. + ## `vm.isContext(object)`