@@ -134,8 +134,8 @@ function* gen() {
134
134
135
135
` .run(val, fn) ` creates a new function body. The new function environment is not
136
136
equivalent to the outer environment and can not trivially share code fragments
137
- between them. Additionally, ` break ` /` continue ` /` return ` can not be
138
- refactored naively.
137
+ between them. Additionally, ` break ` /` continue ` /` return ` can not be refactored
138
+ naively.
139
139
140
140
It would be more intuitive to be able to insert a single line of code to scope
141
141
the ` computeResult ` and ` computeResult2 ` calls with a new AsyncContext value
@@ -278,19 +278,58 @@ not used with `DisposableStack` would have to be added, because
278
278
279
279
As a mitigation to the above issue of manually entering and exiting a scope out
280
280
of sync with the lexical scoping, an alternative proposal is to specialize the
281
- handling of async context variables in ` using ` declarations as follows:
282
-
283
- - In the ` using ` machinery, before calling the ` @@enter ` method, a global flag
284
- would be set that indicates that the ` @@enter ` method is being called from a
285
- ` using ` declaration.
286
- - The ` @@enter ` method implementation would check if the global flag is set. If
287
- it is not, an error would be thrown. If it is set, the ` @@enter ` method would
288
- capture the async context snapshot and set it into a global variable that is
289
- later read from the ` using ` machinery. The ` @@enter ` method would then create
290
- a new async context scope with the new value, and enter it.
291
- - In the ` using ` machinery, after the ` @@enter ` method returns, the global flag
292
- would be cleared, and the value of the value of the global snapshot variable
293
- would be captured.
281
+ handling of async context variables in ` using ` declarations as illustrated by
282
+ this pseudo code:
283
+
284
+ ``` js
285
+ const GLOBAL_STACK = [];
286
+
287
+ function UsingEnter (state , enterMethod ) {
288
+ const current = CaptureSnapshot ();
289
+ GLOBAL_STACK .push (current);
290
+ try {
291
+ enterMethod ();
292
+ } finally {
293
+ const newSnapshot = GLOBAL_STACK .pop ();
294
+ RestoreSnapshot (newSnapshot);
295
+ state .snapshot = current;
296
+ }
297
+ }
298
+
299
+ function UsingExit (state , disposeMethod ) {
300
+ try {
301
+ disposeMethod ();
302
+ } finally {
303
+ RestoreSnapshot (state .snapshot );
304
+ }
305
+ }
306
+
307
+ function AsyncVariableSymbolEnter (variable , value ) {
308
+ const current = GLOBAL_STACK .pop ();
309
+ if (current === undefined ) {
310
+ throw new TypeError (
311
+ " Can not enter an async variable outside of `using`." ,
312
+ );
313
+ }
314
+ const newSnapshot = AddToSnapshot (
315
+ current,
316
+ variable,
317
+ value,
318
+ );
319
+ GLOBAL_STACK .push (newSnapshot);
320
+ }
321
+ ```
322
+
323
+ - In the ` using ` machinery, before calling the ` @@enter ` method, capture the
324
+ current snapshot and push it into a global stack variable.
325
+ - The ` @@enter ` method implementation would check if the global stack contains a
326
+ snapshot. If it does not, an error would be thrown. If it does, the ` @@enter `
327
+ method would create a new snapshot from the top most snapshot in the stack by
328
+ adding the variable, and then set it back into the same slot in the stack.
329
+ This is later read from the ` using ` machinery.
330
+ - In the ` using ` machinery, after the ` @@enter ` method returns, the snapshot is
331
+ removed from the global stack and entered. The original captured current
332
+ snapshot is saved.
294
333
295
334
- In the ` using ` machinery, once the ` using ` declaration lexical scope closes,
296
335
as usual the ` @@dispose ` method is called. Once the ` @@dispose ` method
@@ -303,6 +342,11 @@ declaration. Binding to a lexical scope is enforced, just like with `run`.
303
342
304
343
The proposal does add some additional complexity to the ` using ` machinery.
305
344
345
+ > With this proposal, ` Symbol.enter ` on the ` AsyncContext.Variable#withValue `
346
+ > object would never directly enter a scope, but would instead schedule the
347
+ > enter for when the ` Symbol.enter ` callback is invoked. This is necessary to
348
+ > ensure that the scope with the entered value can not leak out.
349
+
306
350
## Proposal C: enforced disposal through a specialized class
307
351
308
352
As an alternative mitigation to the above issue of manually entering and exiting
0 commit comments