@@ -188,6 +188,9 @@ overhead.
188
188
<!-- YAML
189
189
added: v0.3.1
190
190
changes:
191
+ - version: REPLACEME
192
+ pr-url: https://github.com/nodejs/node/pull/34023
193
+ description: The `microtaskMode` option is supported now.
191
194
- version: v10.0.0
192
195
pr-url: https://github.com/nodejs/node/pull/19016
193
196
description: The `contextCodeGeneration` option is supported now.
@@ -225,6 +228,10 @@ changes:
225
228
` EvalError ` . ** Default:** ` true ` .
226
229
* ` wasm ` {boolean} If set to false any attempt to compile a WebAssembly
227
230
module will throw a ` WebAssembly.CompileError ` . ** Default:** ` true ` .
231
+ * ` microtaskMode ` {string} If set to ` afterEvaluate ` , microtasks (tasks
232
+ scheduled through ` Promise ` s any ` async function ` s) will be run immediately
233
+ after the script has run. They are included in the ` timeout ` and
234
+ ` breakOnSigint ` scopes in that case.
228
235
* Returns: {any} the result of the very last statement executed in the script.
229
236
230
237
First contextifies the given ` contextObject ` , runs the compiled code contained
@@ -846,6 +853,9 @@ function with the given `params`.
846
853
<!-- YAML
847
854
added: v0.3.1
848
855
changes:
856
+ - version: REPLACEME
857
+ pr-url: https:// github.com/nodejs/node/pull/34023
858
+ description: The `microtaskMode` option is supported now.
849
859
- version: v10.0.0
850
860
pr-url: https:// github.com/nodejs/node/pull/19398
851
861
description: The first argument can no longer be a function.
@@ -871,6 +881,10 @@ changes:
871
881
`EvalError`. **Default:** `true`.
872
882
* `wasm` {boolean} If set to false any attempt to compile a WebAssembly
873
883
module will throw a ` WebAssembly.CompileError` . ** Default: ** ` true` .
884
+ * ` microtaskMode` {string} If set to ` afterEvaluate` , microtasks (tasks
885
+ scheduled through ` Promise` s any ` async function` s) will be run immediately
886
+ after a script has run through [` script.runInContext()` ][].
887
+ They are included in the ` timeout` and ` breakOnSigint` scopes in that case.
874
888
* Returns: {Object } contextified object.
875
889
876
890
If given a ` contextObject` , the ` vm.createContext()` method will [prepare
@@ -1002,6 +1016,9 @@ console.log(contextObject);
1002
1016
<!-- YAML
1003
1017
added: v0.3.1
1004
1018
changes:
1019
+ - version: REPLACEME
1020
+ pr-url: https://github.com/nodejs/node/pull/34023
1021
+ description: The `microtaskMode` option is supported now.
1005
1022
- version: v10.0.0
1006
1023
pr-url: https://github.com/nodejs/node/pull/19016
1007
1024
description: The `contextCodeGeneration` option is supported now.
@@ -1068,6 +1085,10 @@ changes:
1068
1085
* Returns: {Module Namespace Object|vm.Module} Returning a `vm.Module` is
1069
1086
recommended in order to take advantage of error tracking, and to avoid
1070
1087
issues with namespaces that contain `then` function exports.
1088
+ * `microtaskMode` {string} If set to `afterEvaluate`, microtasks (tasks
1089
+ scheduled through `Promise`s any `async function`s) will be run immediately
1090
+ after the script has run. They are included in the `timeout` and
1091
+ `breakOnSigint` scopes in that case.
1071
1092
* Returns: {any} the result of the very last statement executed in the script.
1072
1093
1073
1094
The `vm.runInNewContext()` first contextifies the given `contextObject` (or
@@ -1224,13 +1245,13 @@ within which it can operate. The process of creating the V8 Context and
1224
1245
associating it with the ` contextObject` is what this document refers to as
1225
1246
" contextifying" the object.
1226
1247
1227
- ## Timeout limitations when using ` process.nextTick() ` , promises, and ` queueMicrotask() `
1248
+ ## Timeout interactions with asynchronous tasks and Promises
1228
1249
1229
- Because of the internal mechanics of how the ` process.nextTick() ` queue and
1230
- the microtask queue that underlies Promises are implemented within V8 and
1231
- Node . js , it is possible for code running within a context to " escape " the
1232
- ` timeout ` set using ` vm.runInContext() ` , ` vm.runInNewContext() ` , and
1233
- ` vm.runInThisContext() ` .
1250
+ ` Promise ` s and ` async function ` s can schedule tasks run by the JavaScript
1251
+ engine asynchronously . By default, these tasks are run after all JavaScript
1252
+ functions on the current stack are done executing.
1253
+ This allows escaping the functionality of the ` timeout ` and
1254
+ ` breakOnSigint ` options .
1234
1255
1235
1256
For example, the following code executed by ` vm.runInNewContext()` with a
1236
1257
timeout of 5 milliseconds schedules an infinite loop to run after a promise
@@ -1240,21 +1261,52 @@ resolves. The scheduled loop is never interrupted by the timeout:
1240
1261
const vm = require('vm');
1241
1262
1242
1263
function loop() {
1264
+ console.log('entering loop');
1243
1265
while (1) console.log(Date.now());
1244
1266
}
1245
1267
1246
1268
vm.runInNewContext(
1247
- 'Promise.resolve().then(loop);',
1269
+ 'Promise.resolve().then(() => loop() );',
1248
1270
{ loop, console },
1249
1271
{ timeout: 5 }
1250
1272
);
1273
+ // This prints *before* 'entering loop' (!)
1274
+ console.log('done executing');
1251
1275
` ` `
1252
1276
1253
- This issue also occurs when the ` loop() ` call is scheduled using
1254
- the ` process.nextTick() ` and ` queueMicrotask() ` functions.
1277
+ This can be addressed by passing ` microtaskMode: 'afterEvaluate' ` to the code
1278
+ that creates the ` Context ` :
1255
1279
1256
- This issue occurs because all contexts share the same microtask and nextTick
1257
- queues.
1280
+ ` ` ` js
1281
+ const vm = require('vm');
1282
+
1283
+ function loop() {
1284
+ while (1) console.log(Date.now());
1285
+ }
1286
+
1287
+ vm.runInNewContext(
1288
+ 'Promise.resolve().then(() => loop());',
1289
+ { loop, console },
1290
+ { timeout: 5, microtaskMode: 'afterEvaluate' }
1291
+ );
1292
+ ` ` `
1293
+
1294
+ In this case, the microtask scheduled through ` promise.then()` will be run
1295
+ before returning from ` vm.runInNewContext()` , and will be interrupted
1296
+ by the ` timeout` functionality . This applies only to code running in a
1297
+ ` vm.Context` , so e .g . [` vm.runInThisContext()` ][] does not take this option.
1298
+
1299
+ Promise callbacks are entered into the microtask queue of the context in which
1300
+ they were created . For example, if ` () => loop()` is replaced with just ` loop`
1301
+ in the above example, then ` loop` will be pushed into the global microtask
1302
+ queue, because it is a function from the outer (main ) context, and thus will
1303
+ also be able to escape the timeout.
1304
+
1305
+ If asynchronous scheduling functions such as `process.nextTick()`,
1306
+ `queueMicrotask()`, `setTimeout()`, `setImmediate()`, etc. are made available
1307
+ inside a `vm.Context`, functions passed to them will be added to global queues,
1308
+ which are shared by all contexts. Therefore, callbacks passed to those functions
1309
+ are not controllable through the timeout either.
1258
1310
1259
1311
[`ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING`]: errors.html#ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING
1260
1312
[`ERR_VM_MODULE_STATUS`]: errors.html#ERR_VM_MODULE_STATUS
0 commit comments