Stage 1 Draft / March 6, 2024

AsyncContext

1 ECMAScript Data Types and Values

1.1 ECMAScript Specification Types

1.1.1 The Async Context Mapping Record Specification Type

The Async Context Mapping Record type is used to represent an AsyncContext.Variable value mapping in the surrounding Agent's [[AsyncContextMapping]].

An Async Context Mapping Record's fields are defined by Table 1.

Table 1: Async Context Mapping Record Fields
Field Name Value Meaning
[[AsyncContextKey]] an AsyncContext.Variable instance The AsyncContext.Variable instance as the key in the mapping.
[[AsyncContextValue]] an ECMAScript language value The value of the AsyncContext.Variable instance in the mapping.

2 Executable Code and Execution Contexts

2.1 Agents

This proposal adds a new field to the Agent Record as the following table:

Table 2: Agent Record Fields
Field Name Value Meaning
[[LittleEndian]] a Boolean The default value computed for the isLittleEndian parameter when it is needed by the algorithms GetValueFromBuffer and SetValueInBuffer. The choice is implementation-defined and should be the alternative that is most efficient for the implementation. Once the value has been observed it cannot change.
[[CanBlock]] a Boolean Determines whether the agent can block or not.
[[Signifier]] an agent signifier Uniquely identifies the agent within its agent cluster.
[[IsLockFree1]] a Boolean true if atomic operations on one-byte values are lock-free, false otherwise.
[[IsLockFree2]] a Boolean true if atomic operations on two-byte values are lock-free, false otherwise.
[[IsLockFree8]] a Boolean true if atomic operations on eight-byte values are lock-free, false otherwise.
[[CandidateExecution]] a candidate execution Record See the memory model.
[[KeptAlive]] a List of Objects Initially a new empty List, representing the list of objects to be kept alive until the end of the current Job
[[AsyncContextMapping]] a List of Async Context Mapping Records A map from the AsyncContext.Variable instances to the saved ECMAScript language value. Every Record in the List contains a unique [[AsyncContextKey]]. The map is initially empty.

2.2 CleanupFinalizationRegistry ( finalizationRegistry )

The abstract operation CleanupFinalizationRegistry takes argument finalizationRegistry (a FinalizationRegistry) and returns either a normal completion containing unused or a throw completion. It performs the following steps when called:

  1. Assert: finalizationRegistry has [[Cells]] and [[CleanupCallback]] internal slots.
  2. Assert: finalizationRegistry has [[Cells]], [[CleanupCallback]], and [[FinalizationRegistryAsyncContextSnapshot]] internal slots.
  3. Let callback be finalizationRegistry.[[CleanupCallback]].
  4. While finalizationRegistry.[[Cells]] contains a Record cell such that cell.[[WeakRefTarget]] is empty, an implementation may perform the following steps:
    1. Choose any such cell.
    2. Remove cell from finalizationRegistry.[[Cells]].
    3. Perform ? HostCallJobCallback(callback, undefined, « cell.[[HeldValue]] »).
    4. Let previousContextMapping be AsyncContextSwap(finalizationRegistry.[[FinalizationRegistryAsyncContextSnapshot]]).
    5. Let result be Completion(HostCallJobCallback(callback, undefined, « cell.[[HeldValue]] »)).
    6. AsyncContextSwap(previousContextMapping).
    7. Perform ? result.
  5. Return unused.

3 ECMAScript Language: Functions and Classes

3.1 Generator Function Definitions

3.1.1 Runtime Semantics: EvaluateGeneratorBody

The syntax-directed operation EvaluateGeneratorBody takes arguments functionObject (a function object) and argumentsList (a List of ECMAScript language values) and returns a throw completion or a return completion. It is defined piecewise over the following productions:

GeneratorBody : FunctionBody
  1. Perform ? FunctionDeclarationInstantiation(functionObject, argumentsList).
  2. Let G be ? OrdinaryCreateFromConstructor(functionObject, "%GeneratorFunction.prototype.prototype%", « [[GeneratorState]], [[GeneratorContext]], [[GeneratorAsyncContextMapping]], [[GeneratorBrand]] »).
  3. Set G.[[GeneratorBrand]] to empty.
  4. Perform GeneratorStart(G, FunctionBody).
  5. Return Completion Record { [[Type]]: return, [[Value]]: G, [[Target]]: empty }.

3.2 Async Generator Function Definitions

3.2.1 Runtime Semantics: EvaluateAsyncGeneratorBody

The syntax-directed operation EvaluateAsyncGeneratorBody takes arguments functionObject (a function object) and argumentsList (a List of ECMAScript language values) and returns a throw completion or a return completion. It is defined piecewise over the following productions:

AsyncGeneratorBody : FunctionBody
  1. Perform ? FunctionDeclarationInstantiation(functionObject, argumentsList).
  2. Let generator be ? OrdinaryCreateFromConstructor(functionObject, "%AsyncGeneratorFunction.prototype.prototype%", « [[AsyncGeneratorState]], [[AsyncGeneratorContext]], [[AsyncGeneratorQueue]], [[AsyncGeneratorAsyncContextMapping]], [[GeneratorBrand]] »).
  3. Set generator.[[GeneratorBrand]] to empty.
  4. Perform AsyncGeneratorStart(generator, FunctionBody).
  5. Return Completion Record { [[Type]]: return, [[Value]]: generator, [[Target]]: empty }.

4 Control Abstraction Objects

4.1 Promise Objects

4.1.1 Promise Abstract Operations

4.1.1.1 PromiseReaction Records

A PromiseReaction Record is a Record value used to store information about how a promise should react when it becomes resolved or rejected with a given value. PromiseReaction Records are created by the PerformPromiseThen abstract operation, and are used by the Abstract Closure returned by NewPromiseReactionJob.

PromiseReaction Records have the fields listed in Table 3.

Table 3: PromiseReaction Record Fields
Field Name Value Meaning
[[Capability]] a PromiseCapability Record or undefined The capabilities of the promise for which this record provides a reaction handler.
[[Type]] fulfill or reject The [[Type]] is used when [[Handler]] is empty to allow for behaviour specific to the settlement type.
[[Handler]] a JobCallback Record or empty The function that should be applied to the incoming value, and whose return value will govern what happens to the derived promise. If [[Handler]] is empty, a function that depends on the value of [[Type]] will be used instead.
[[PromiseAsyncContextSnapshot]] a List of Async Context Mapping Records A map from the AsyncContext.Variable instances to the saved ECMAScript language value. Every Record in the List contains a unique [[AsyncContextKey]].

4.1.1.2 HostPromiseRejectionTracker ( promise, operation )

The host-defined abstract operation HostPromiseRejectionTracker takes arguments promise (a Promise) and operation ("reject" or "handle") and returns unused. It allows host environments to track promise rejections.

An implementation of HostPromiseRejectionTracker must conform to the following requirements:

The default implementation of HostPromiseRejectionTracker is to return unused.

Note

An implementation of HostPromiseRejectionTracker that delays notifying developers of unhandled rejections must conform to the following requirements

4.1.2 Promise Jobs

4.1.2.1 NewPromiseReactionJob ( reaction, argument )

The abstract operation NewPromiseReactionJob takes arguments reaction (a PromiseReaction Record) and argument (an ECMAScript language value) and returns a Record with fields [[Job]] (a Job Abstract Closure) and [[Realm]] (a Realm Record or null). It returns a new Job Abstract Closure that applies the appropriate handler to the incoming value, and uses the handler's return value to resolve or reject the derived promise associated with that handler. It performs the following steps when called:

  1. Let job be a new Job Abstract Closure with no parameters that captures reaction and argument and performs the following steps when called:
    1. Let promiseCapability be reaction.[[Capability]].
    2. Let type be reaction.[[Type]].
    3. Let handler be reaction.[[Handler]].
    4. Let previousContextMapping be AsyncContextSwap(reaction.[[PromiseAsyncContextSnapshot]]).
    5. If handler is empty, then
      1. If type is fulfill, then
        1. let handlerResult be NormalCompletion(argument).
      2. Else,
        1. Assert: type is reject.
        2. Let handlerResult be ThrowCompletion(argument).
    6. Else,
      1. let handlerResult be Completion(HostCallJobCallback(handler, undefined, « argument »)).
    7. If promiseCapability is undefined, then
      1. Assert: handlerResult is not an abrupt completion.
      2. AsyncContextSwap(previousContextMapping).
      3. Return empty.
    8. Assert: promiseCapability is a PromiseCapability Record.
    9. If handlerResult is an abrupt completion, then
      1. Return ? Call(promiseCapability.[[Reject]], undefined, « handlerResult.[[Value]] »).
      2. Let resolvingFunctionResult be Completion(Call(promiseCapability.[[Reject]], undefined, « handlerResult.[[Value]] »)).
    10. Else,
      1. Return ? Call(promiseCapability.[[Resolve]], undefined, « handlerResult.[[Value]] »).
      2. Let resolvingFunctionResult be Completion(Call(promiseCapability.[[Resolve]], undefined, « handlerResult.[[Value]] »)).
    11. AsyncContextSwap(previousContextMapping).
    12. Return resolvingFunctionResult.
  2. Let handlerRealm be null.
  3. If reaction.[[Handler]] is not empty, then
    1. Let getHandlerRealmResult be Completion(GetFunctionRealm(reaction.[[Handler]].[[Callback]])).
    2. If getHandlerRealmResult is a normal completion, set handlerRealm to getHandlerRealmResult.[[Value]].
    3. Else, set handlerRealm to the current Realm Record.
    4. NOTE: handlerRealm is never null unless the handler is undefined. When the handler is a revoked Proxy and no ECMAScript code runs, handlerRealm is used to create error objects.
  4. Return the Record { [[Job]]: job, [[Realm]]: handlerRealm }.

4.1.2.2 NewPromiseResolveThenableJob ( promiseToResolve, thenable, then )

The abstract operation NewPromiseResolveThenableJob takes arguments promiseToResolve (a Promise), thenable (an Object), and then (a JobCallback Record) and returns a Record with fields [[Job]] (a Job Abstract Closure) and [[Realm]] (a Realm Record). It performs the following steps when called:

  1. Let snapshot be AsyncContextSnapshot().
  2. Let job be a new Job Abstract Closure with no parameters that captures promiseToResolve, thenable, then, and snapshot and performs the following steps when called:
    1. Let resolvingFunctions be CreateResolvingFunctions(promiseToResolve).
    2. Let previousContextMapping be AsyncContextSwap(snapshot).
    3. Let thenCallResult be Completion(HostCallJobCallback(then, thenable, « resolvingFunctions.[[Resolve]], resolvingFunctions.[[Reject]] »)).
    4. If thenCallResult is an abrupt completion, then
      1. Return ? Call(resolvingFunctions.[[Reject]], undefined, « thenCallResult.[[Value]] »).
      2. Let rejectResult be Completion(Call(resolvingFunctions.[[Reject]], undefined, « thenCallResult.[[Value]] »)).
      3. AsyncContextSwap(previousContextMapping).
      4. Return rejectResult.
    5. AsyncContextSwap(previousContextMapping).
    6. Return ? thenCallResult.
  3. Let getThenRealmResult be Completion(GetFunctionRealm(then.[[Callback]])).
  4. If getThenRealmResult is a normal completion, let thenRealm be getThenRealmResult.[[Value]].
  5. Else, let thenRealm be the current Realm Record.
  6. NOTE: thenRealm is never null. When then.[[Callback]] is a revoked Proxy and no code runs, thenRealm is used to create error objects.
  7. Return the Record { [[Job]]: job, [[Realm]]: thenRealm }.
Note

This Job uses the supplied thenable and its then method to resolve the given promise. This process must take place as a Job to ensure that the evaluation of the then method occurs after evaluation of any surrounding code has completed.

4.1.3 Properties of the Promise Prototype Object

The Promise prototype object:

  • is %Promise.prototype%.
  • has a [[Prototype]] internal slot whose value is %Object.prototype%.
  • is an ordinary object.
  • does not have a [[PromiseState]] internal slot or any of the other internal slots of Promise instances.

4.1.3.1 Promise.prototype.then ( onFulfilled, onRejected )

This method performs the following steps when called:

  1. Let promise be the this value.
  2. If IsPromise(promise) is false, throw a TypeError exception.
  3. Let C be ? SpeciesConstructor(promise, %Promise%).
  4. Let resultCapability be ? NewPromiseCapability(C).
  5. Return PerformPromiseThen(promise, onFulfilled, onRejected, resultCapability).

4.1.3.1.1 PerformPromiseThen ( promise, onFulfilled, onRejected [ , resultCapability ] )

The abstract operation PerformPromiseThen takes arguments promise (a Promise), onFulfilled (an ECMAScript language value), and onRejected (an ECMAScript language value) and optional argument resultCapability (a PromiseCapability Record) and returns an ECMAScript language value. It performs the “then” operation on promise using onFulfilled and onRejected as its settlement actions. If resultCapability is passed, the result is stored by updating resultCapability's promise. If it is not passed, then PerformPromiseThen is being called by a specification-internal operation where the result does not matter. It performs the following steps when called:

  1. Assert: IsPromise(promise) is true.
  2. If resultCapability is not present, then
    1. Set resultCapability to undefined.
  3. If IsCallable(onFulfilled) is false, then
    1. Let onFulfilledJobCallback be empty.
  4. Else,
    1. Let onFulfilledJobCallback be HostMakeJobCallback(onFulfilled).
  5. If IsCallable(onRejected) is false, then
    1. Let onRejectedJobCallback be empty.
  6. Else,
    1. Let onRejectedJobCallback be HostMakeJobCallback(onRejected).
  7. Let snapshot be AsyncContextSnapshot().
  8. Let fulfillReaction be the PromiseReaction Record { [[Capability]]: resultCapability, [[Type]]: fulfill, [[Handler]]: onFulfilledJobCallback, [[PromiseAsyncContextSnapshot]]: snapshot }.
  9. Let rejectReaction be the PromiseReaction Record { [[Capability]]: resultCapability, [[Type]]: reject, [[Handler]]: onRejectedJobCallback, [[PromiseAsyncContextSnapshot]]: snapshot}.
  10. If promise.[[PromiseState]] is pending, then
    1. Append fulfillReaction to promise.[[PromiseFulfillReactions]].
    2. Append rejectReaction to promise.[[PromiseRejectReactions]].
  11. Else if promise.[[PromiseState]] is fulfilled, then
    1. Let value be promise.[[PromiseResult]].
    2. Let fulfillJob be NewPromiseReactionJob(fulfillReaction, value).
    3. Perform HostEnqueuePromiseJob(fulfillJob.[[Job]], fulfillJob.[[Realm]]).
  12. Else,
    1. Assert: The value of promise.[[PromiseState]] is rejected.
    2. Let reason be promise.[[PromiseResult]].
    3. If promise.[[PromiseIsHandled]] is false, perform HostPromiseRejectionTracker(promise, "handle").
    4. Let rejectJob be NewPromiseReactionJob(rejectReaction, reason).
    5. Perform HostEnqueuePromiseJob(rejectJob.[[Job]], rejectJob.[[Realm]]).
  13. Set promise.[[PromiseIsHandled]] to true.
  14. If resultCapability is undefined, then
    1. Return undefined.
  15. Else,
    1. Return resultCapability.[[Promise]].

4.2 Generator Objects

4.2.1 Properties of Generator Instances

Generator instances are initially created with the internal slots described in Table 4.

Table 4: Internal Slots of Generator Instances
Internal Slot Type Description
[[GeneratorState]] undefined, suspendedStart, suspendedYield, executing, or completed The current execution state of the generator.
[[GeneratorContext]] an execution context The execution context that is used when executing the code of this generator.
[[GeneratorAsyncContextMapping]] a List of Async Context Mapping Records or empty The value of the agent's [[AsyncContextMapping]] to use the next time this generator is resumed.
[[GeneratorBrand]] a String or empty A brand used to distinguish different kinds of generators. The [[GeneratorBrand]] of generators declared by ECMAScript source text is always empty.

4.2.2 Generator Abstract Operations

4.2.2.1 GeneratorStart ( generator, generatorBody )

The abstract operation GeneratorStart takes arguments generator (a Generator) and generatorBody (a FunctionBody Parse Node or an Abstract Closure with no parameters) and returns unused. It performs the following steps when called:

  1. Assert: The value of generator.[[GeneratorState]] is undefined.
  2. Let genContext be the running execution context.
  3. Set the Generator component of genContext to generator.
  4. Let closure be a new Abstract Closure with no parameters that captures generatorBody and performs the following steps when called:
    1. Let acGenContext be the running execution context.
    2. Let acGenerator be the Generator component of acGenContext.
    3. If generatorBody is a Parse Node, then
      1. Let result be Completion(Evaluation of generatorBody).
    4. Else,
      1. Assert: generatorBody is an Abstract Closure with no parameters.
      2. Let result be generatorBody().
    5. Assert: If we return here, the generator either threw an exception or performed either an implicit or explicit return.
    6. Remove acGenContext from the execution context stack and restore the execution context that is at the top of the execution context stack as the running execution context.
    7. Set acGenerator.[[GeneratorState]] to completed.
    8. NOTE: Once a generator enters the completed state it never leaves it and its associated execution context is never resumed. Any execution state associated with acGenerator can be discarded at this point.
    9. If result.[[Type]] is normal, then
      1. Let resultValue be undefined.
    10. Else if result.[[Type]] is return, then
      1. Let resultValue be result.[[Value]].
    11. Else,
      1. Assert: result.[[Type]] is throw.
      2. Return ? result.
    12. Return CreateIterResultObject(resultValue, true).
  5. Set the code evaluation state of genContext such that when evaluation is resumed for that execution context, closure will be called with no arguments.
  6. Set generator.[[GeneratorContext]] to genContext.
  7. If generatorBody is a FunctionBody Parse Node, then
    1. Set generator.[[GeneratorAsyncContextMapping]] to AsyncContextSnapshot().
  8. Else,
    1. Set generator.[[GeneratorAsyncContextMapping]] to empty.
  9. Set generator.[[GeneratorState]] to suspended-start.
  10. Return unused.

4.2.2.2 GeneratorValidate ( generator, generatorBrand )

The abstract operation GeneratorValidate takes arguments generator (an ECMAScript language value) and generatorBrand (a String or empty) and returns either a normal completion containing one of suspendedStart, suspendedYield, or completed, or a throw completion. It performs the following steps when called:

  1. Perform ? RequireInternalSlot(generator, [[GeneratorState]]).
  2. Perform ? RequireInternalSlot(generator, [[GeneratorBrand]]).
  3. If generator.[[GeneratorBrand]] is not generatorBrand, throw a TypeError exception.
  4. Assert: generator also has a [[GeneratorContext]] internal slot.
  5. Assert: generator also has [[GeneratorContext]] and [[GeneratorAsyncContextMapping]] internal slots.
  6. Let state be generator.[[GeneratorState]].
  7. If state is executing, throw a TypeError exception.
  8. Return state.

4.2.2.3 GeneratorResume ( generator, value, generatorBrand )

The abstract operation GeneratorResume takes arguments generator (an ECMAScript language value), value (an ECMAScript language value or empty), and generatorBrand (a String or empty) and returns either a normal completion containing an ECMAScript language value or a throw completion. It performs the following steps when called:

  1. Let state be ? GeneratorValidate(generator, generatorBrand).
  2. If state is completed, return CreateIterResultObject(undefined, true).
  3. Assert: state is either suspended-start or suspended-yield.
  4. Let genContext be generator.[[GeneratorContext]].
  5. Let methodContext be the running execution context.
  6. Suspend methodContext.
  7. Set generator.[[GeneratorState]] to executing.
  8. If generator.[[GeneratorAsyncContextMapping]] is empty, then
    1. Let previousContextMapping be empty.
  9. Else,
    1. Let previousContextMapping be AsyncContextSwap(generator.[[GeneratorAsyncContextMapping]]).
  10. Push genContext onto the execution context stack; genContext is now the running execution context.
  11. Resume the suspended evaluation of genContext using NormalCompletion(value) as the result of the operation that suspended it. Let result be the value returned by the resumed computation.
  12. Assert: When we return here, genContext has already been removed from the execution context stack and methodContext is the currently running execution context.
  13. If previousContextMapping is not empty, then
    1. Assert: The result of AsyncContextSnapshot() is generator.[[GeneratorAsyncContextMapping]].
    2. AsyncContextSwap(previousContextMapping).
  14. Return ? result.

4.2.2.4 GeneratorResumeAbrupt ( generator, abruptCompletion, generatorBrand )

The abstract operation GeneratorResumeAbrupt takes arguments generator (an ECMAScript language value), abruptCompletion (a return completion or a throw completion), and generatorBrand (a String or empty) and returns either a normal completion containing an ECMAScript language value or a throw completion. It performs the following steps when called:

  1. Let state be ? GeneratorValidate(generator, generatorBrand).
  2. If state is suspended-start, then
    1. Set generator.[[GeneratorState]] to completed.
    2. NOTE: Once a generator enters the completed state it never leaves it and its associated execution context is never resumed. Any execution state associated with generator can be discarded at this point.
    3. Set state to completed.
  3. If state is completed, then
    1. If abruptCompletion.[[Type]] is return, then
      1. Return CreateIterResultObject(abruptCompletion.[[Value]], true).
    2. Return ? abruptCompletion.
  4. Assert: state is suspended-yield.
  5. Let genContext be generator.[[GeneratorContext]].
  6. Let methodContext be the running execution context.
  7. Suspend methodContext.
  8. Set generator.[[GeneratorState]] to executing.
  9. If generator.[[GeneratorAsyncContextMapping]] is empty, then
    1. Let previousContextMapping be empty.
  10. Else,
    1. Let previousContextMapping be AsyncContextSwap(generator.[[GeneratorAsyncContextMapping]]).
  11. Push genContext onto the execution context stack; genContext is now the running execution context.
  12. Resume the suspended evaluation of genContext using abruptCompletion as the result of the operation that suspended it. Let result be the Completion Record returned by the resumed computation.
  13. Assert: When we return here, genContext has already been removed from the execution context stack and methodContext is the currently running execution context.
  14. If previousContextMapping is not empty, then
    1. Assert: The result of AsyncContextSnapshot() is generator.[[GeneratorAsyncContextMapping]].
    2. AsyncContextSwap(previousContextMapping).
  15. Return ? result.

4.2.2.5 CreateIteratorFromClosure ( closure, generatorBrand, generatorPrototype )

The abstract operation CreateIteratorFromClosure takes arguments closure (an Abstract Closure with no parameters), generatorBrand (a String or empty), and generatorPrototype (an Object) and returns a Generator. It performs the following steps when called:

  1. NOTE: closure can contain uses of the Yield operation to yield an IteratorResult object.
  2. Let internalSlotsList be « [[GeneratorState]], [[GeneratorContext]], [[GeneratorAsyncContextMapping]], [[GeneratorBrand]] ».
  3. Let generator be OrdinaryObjectCreate(generatorPrototype, internalSlotsList).
  4. Set generator.[[GeneratorBrand]] to generatorBrand.
  5. Set generator.[[GeneratorState]] to undefined.
  6. Let callerContext be the running execution context.
  7. Let calleeContext be a new execution context.
  8. Set the Function of calleeContext to null.
  9. Set the Realm of calleeContext to the current Realm Record.
  10. Set the ScriptOrModule of calleeContext to callerContext's ScriptOrModule.
  11. If callerContext is not already suspended, suspend callerContext.
  12. Push calleeContext onto the execution context stack; calleeContext is now the running execution context.
  13. Perform GeneratorStart(generator, closure).
  14. Remove calleeContext from the execution context stack and restore callerContext as the running execution context.
  15. Return generator.

4.3 AsyncGenerator Objects

4.3.1 Properties of AsyncGenerator Instances

AsyncGenerator instances are initially created with the internal slots described below:

Table 5: Internal Slots of AsyncGenerator Instances
Internal Slot Type Description
[[AsyncGeneratorState]] undefined, suspendedStart, suspendedYield, executing, awaiting-return, or completed The current execution state of the async generator.
[[AsyncGeneratorContext]] an execution context The execution context that is used when executing the code of this async generator.
[[AsyncGeneratorQueue]] a List of AsyncGeneratorRequest Records Records which represent requests to resume the async generator. Except during state transitions, it is non-empty if and only if [[AsyncGeneratorState]] is either executing or awaiting-return.
[[AsyncGeneratorAsyncContextMapping]] a List of Async Context Mapping Records or empty The value of the agent's [[AsyncContextMapping]] to use the next time this generator is resumed.
[[GeneratorBrand]] a String or empty A brand used to distinguish different kinds of async generators. The [[GeneratorBrand]] of async generators declared by ECMAScript source text is always empty.

4.3.2 AsyncGenerator Abstract Operations

4.3.2.1 AsyncGeneratorStart ( generator, generatorBody )

The abstract operation AsyncGeneratorStart takes arguments generator (an AsyncGenerator) and generatorBody (a FunctionBody Parse Node or an Abstract Closure with no parameters) and returns unused. It performs the following steps when called:

  1. Assert: generator.[[AsyncGeneratorState]] is undefined.
  2. Let genContext be the running execution context.
  3. Set the Generator component of genContext to generator.
  4. Let closure be a new Abstract Closure with no parameters that captures generatorBody and performs the following steps when called:
    1. Let acGenContext be the running execution context.
    2. Let acGenerator be the Generator component of acGenContext.
    3. If generatorBody is a Parse Node, then
      1. Let result be Completion(Evaluation of generatorBody).
    4. Else,
      1. Assert: generatorBody is an Abstract Closure with no parameters.
      2. Let result be Completion(generatorBody()).
    5. Assert: If we return here, the async generator either threw an exception or performed either an implicit or explicit return.
    6. Remove acGenContext from the execution context stack and restore the execution context that is at the top of the execution context stack as the running execution context.
    7. Set acGenerator.[[AsyncGeneratorState]] to completed.
    8. If result.[[Type]] is normal, set result to NormalCompletion(undefined).
    9. If result.[[Type]] is return, set result to NormalCompletion(result.[[Value]]).
    10. Perform AsyncGeneratorCompleteStep(acGenerator, result, true).
    11. Perform AsyncGeneratorDrainQueue(acGenerator).
    12. Return undefined.
  5. Set the code evaluation state of genContext such that when evaluation is resumed for that execution context, closure will be called with no arguments.
  6. Set generator.[[AsyncGeneratorContext]] to genContext.
  7. Set generator.[[AsyncGeneratorState]] to suspended-start.
  8. Set generator.[[AsyncGeneratorQueue]] to a new empty List.
  9. If generatorBody is a FunctionBody Parse Node, then
    1. Set generator.[[AsyncGeneratorAsyncContextMapping]] to AsyncContextSnapshot().
  10. Else,
    1. Set generator.[[AsyncGeneratorAsyncContextMapping]] to empty.
  11. Return unused.

4.3.2.2 AsyncGeneratorValidate ( generator, generatorBrand )

The abstract operation AsyncGeneratorValidate takes arguments generator (an ECMAScript language value) and generatorBrand (a String or empty) and returns either a normal completion containing unused or a throw completion. It performs the following steps when called:

  1. Perform ? RequireInternalSlot(generator, [[AsyncGeneratorContext]]).
  2. Perform ? RequireInternalSlot(generator, [[AsyncGeneratorState]]).
  3. Perform ? RequireInternalSlot(generator, [[AsyncGeneratorQueue]]).
  4. Perform ? RequireInternalSlot(generator, [[AsyncGeneratorAsyncContextMapping]]).
  5. If generator.[[GeneratorBrand]] is not generatorBrand, throw a TypeError exception.
  6. Return unused.

4.3.2.3 AsyncGeneratorResume ( generator, completion )

The abstract operation AsyncGeneratorResume takes arguments generator (an AsyncGenerator) and completion (a Completion Record) and returns unused. It performs the following steps when called:

  1. Assert: generator.[[AsyncGeneratorState]] is either suspended-start or suspended-yield.
  2. Let genContext be generator.[[AsyncGeneratorContext]].
  3. Let callerContext be the running execution context.
  4. Suspend callerContext.
  5. Set generator.[[AsyncGeneratorState]] to executing.
  6. If generator.[[AsyncGeneratorAsyncContextMapping]] is empty, then
    1. Let previousContextMapping be empty.
  7. Else,
    1. Let previousContextMapping be AsyncContextSwap(generator.[[AsyncGeneratorAsyncContextMapping]]).
  8. Push genContext onto the execution context stack; genContext is now the running execution context.
  9. Resume the suspended evaluation of genContext using completion as the result of the operation that suspended it. Let result be the Completion Record returned by the resumed computation.
  10. Assert: result is never an abrupt completion.
  11. Assert: When we return here, genContext has already been removed from the execution context stack and callerContext is the currently running execution context.
  12. If previousContextMapping is not empty, then
    1. Assert: The result of AsyncContextSnapshot() is generator.[[AsyncGeneratorAsyncContextMapping]].
    2. AsyncContextSwap(previousContextMapping).
  13. Return unused.

4.3.2.4 CreateAsyncIteratorFromClosure ( closure, generatorBrand, generatorPrototype )

The abstract operation CreateAsyncIteratorFromClosure takes arguments closure (an Abstract Closure with no parameters), generatorBrand (a String or empty), and generatorPrototype (an Object) and returns an AsyncGenerator. It performs the following steps when called:

  1. NOTE: closure can contain uses of the Await operation and uses of the Yield operation to yield an IteratorResult object.
  2. Let internalSlotsList be « [[AsyncGeneratorState]], [[AsyncGeneratorContext]], [[AsyncGeneratorQueue]], [[AsyncGeneratorAsyncContextMapping]], [[GeneratorBrand]] ».
  3. Let generator be OrdinaryObjectCreate(generatorPrototype, internalSlotsList).
  4. Set generator.[[GeneratorBrand]] to generatorBrand.
  5. Set generator.[[AsyncGeneratorState]] to undefined.
  6. Let callerContext be the running execution context.
  7. Let calleeContext be a new execution context.
  8. Set the Function of calleeContext to null.
  9. Set the Realm of calleeContext to the current Realm Record.
  10. Set the ScriptOrModule of calleeContext to callerContext's ScriptOrModule.
  11. If callerContext is not already suspended, suspend callerContext.
  12. Push calleeContext onto the execution context stack; calleeContext is now the running execution context.
  13. Perform AsyncGeneratorStart(generator, closure).
  14. Remove calleeContext from the execution context stack and restore callerContext as the running execution context.
  15. Return generator.

4.4 The AsyncContext Object

The AsyncContext object:

  • is the intrinsic object %AsyncContext%.
  • is the initial value of the "AsyncContext" property of the global object.
  • is an ordinary object.
  • has a [[Prototype]] internal slot whose value is %Object.prototype%.
  • is not a function object.
  • does not have a [[Construct]] internal method; it cannot be used as a constructor with the new operator.
  • does not have a [[Call]] internal method; it cannot be invoked as a function.

4.4.1 AsyncContext Abstract Operations

4.4.1.1 AsyncContextSnapshot ( )

The abstract operation AsyncContextSnapshot takes no arguments and returns a List of Async Context Mapping Records. It is used to snapshot the surrounding agent's Agent Record's [[AsyncContextMapping]]. It performs the following steps when called:

  1. Let agentRecord be the surrounding agent's Agent Record.
  2. Return agentRecord.[[AsyncContextMapping]].

4.4.1.2 AsyncContextSwap ( snapshotMapping )

The abstract operation AsyncContextSwap takes argument snapshotMapping (a List of Async Context Mapping Records) and returns a List of Async Context Mapping Records. It is used to swap the surrounding agent's Agent Record's [[AsyncContextMapping]] with the snapshotMapping. It performs the following steps when called:

  1. Let agentRecord be the surrounding agent's Agent Record.
  2. Let asyncContextMapping be agentRecord.[[AsyncContextMapping]].
  3. Set agentRecord.[[AsyncContextMapping]] to snapshotMapping.
  4. Return asyncContextMapping.

4.4.2 Constructor Properties of the AsyncContext Object

4.4.2.1 AsyncContext.Snapshot ( . . . )

See 4.5.

4.4.2.2 AsyncContext.Variable ( . . . )

See 4.6.

4.4.3 Value Properties of the AsyncContext Object

4.4.3.1 AsyncContext [ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "AsyncContext".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

4.5 AsyncContext.Snapshot Objects

4.5.1 The AsyncContext.Snapshot Constructor

The AsyncContext.Snapshot constructor:

  • is %AsyncContext.Snapshot%.
  • is the initial value of the "Snapshot" property of the %AsyncContext% object.
  • creates and initializes a new AsyncContext.Snapshot when called as a constructor.
  • is not intended to be called as a function and will throw an exception when called in that manner.
  • may be used as the value in an extends clause of a class definition. Subclass constructors that intend to inherit the specified AsyncContext.Snapshot behaviour must include a super call to the AsyncContext.Snapshot constructor to create and initialize the subclass instance with the internal state necessary to support the AsyncContext.Snapshot and AsyncContext.Snapshot.prototype built-in methods.

4.5.1.1 AsyncContext.Snapshot ( )

This function performs the following steps when called:

  1. If NewTarget is undefined, throw a TypeError exception.
  2. Let snapshotMapping be AsyncContextSnapshot().
  3. Let asyncSnapshot be ? OrdinaryCreateFromConstructor(NewTarget, "%AsyncContext.Snapshot.prototype%", « [[AsyncSnapshotMapping]] »).
  4. Set asyncSnapshot.[[AsyncSnapshotMapping]] to snapshotMapping.
  5. Return asyncSnapshot.

4.5.2 Properties of the AsyncContext.Snapshot Constructor

The AsyncContext.Snapshot constructor:

  • has a [[Prototype]] internal slot whose value is %Function.prototype%.
  • has the following properties:

4.5.2.1 AsyncContext.Snapshot.prototype

The initial value of AsyncContext.Snapshot.prototype is the AsyncContext.Snapshot prototype object.

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.

4.5.2.2 AsyncContext.Snapshot.wrap ( fn )

This function returns a new function which restores the current value of all AsyncContext.Variable values when being invoked.

  1. If IsCallable(fn) is false, throw a TypeError exception.
  2. Let snapshot be AsyncContextSnapshot().
  3. Let closure be a new Abstract Closure with parameters (...args) that captures fn and snapshot and performs the following steps when called:
    1. Let thisArgument be the this value.
    2. Let previousContextMapping be AsyncContextSwap(snapshot).
    3. Let result be Completion(Call(fn, thisArgument, args)).
    4. AsyncContextSwap(previousContextMapping).
    5. Return result.
  4. Let length be ? LengthOfArrayLike(fn).
  5. Let name be ? Get(fn, "name").
  6. If name is not a String, set name to the empty String.
  7. Let realm be the current Realm Record.
  8. Let prototype be realm.[[Intrinsics]].[[%Function.prototype%]].
  9. Return CreateBuiltinFunction(closure, length, name, « », realm, prototype, "wrapped").

4.5.3 Properties of the AsyncContext.Snapshot Prototype Object

The AsyncContext.Snapshot prototype object:

  • is %AsyncContext.Snapshot.prototype%.
  • has a [[Prototype]] internal slot whose value is %Object.prototype%.
  • is an ordinary object.
  • does not have any of the other internal slots of AsyncContext.Snapshot instances.

4.5.3.1 AsyncContext.Snapshot.prototype.constructor

The initial value of AsyncContext.Snapshot.prototype.constructor is %AsyncContext.Snapshot%.

4.5.3.2 AsyncContext.Snapshot.prototype.run ( func, ...args )

This method performs the following steps when called:

  1. Let asyncSnapshot be the this value.
  2. Perform ? RequireInternalSlot(asyncSnapshot, [[AsyncSnapshotMapping]]).
  3. Let previousContextMapping be AsyncContextSwap(asyncSnapshot.[[AsyncSnapshotMapping]]).
  4. Let result be Completion(Call(func, undefined, args)).
  5. AsyncContextSwap(previousContextMapping).
  6. Return result.

4.5.3.3 AsyncContext.Snapshot.prototype [ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "AsyncContext.Snapshot".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

4.5.4 Properties of AsyncContext.Snapshot Instances

AsyncContext.Snapshot instances are ordinary objects that inherit properties from the AsyncContext.Snapshot prototype object (the intrinsic, %AsyncContext.Snapshot.prototype%). AsyncContext.Snapshot instances are initially created with the internal slots described in Table 6.

Table 6: Internal Slots of AsyncContext-Snapshot Instances
Internal Slot Type Description
[[AsyncSnapshotMapping]] a List of Async Context Mapping Records Represents the snapshotted surrounding agent's Agent Record's [[AsyncContextMapping]] of the AsyncContext.Snapshot instance.

4.6 AsyncContext.Variable Objects

4.6.1 The AsyncContext.Variable Constructor

The AsyncContext.Variable constructor:

  • is %AsyncContext.Variable%.
  • is the initial value of the "Variable" property of the %AsyncContext% object.
  • creates and initializes a new AsyncContext.Variable when called as a constructor.
  • is not intended to be called as a function and will throw an exception when called in that manner.
  • may be used as the value in an extends clause of a class definition. Subclass constructors that intend to inherit the specified AsyncContext.Variable behaviour must include a super call to the AsyncContext.Variable constructor to create and initialize the subclass instance with the internal state necessary to support the AsyncContext.Variable.prototype built-in methods.

4.6.1.1 AsyncContext.Variable ( options )

This function performs the following steps when called:

  1. If NewTarget is undefined, throw a TypeError exception.
  2. Let nameStr be the empty String.
  3. Let defaultValue be undefined.
  4. If options is an Object, then
    1. Let namePresent be ? HasProperty(options, "name").
    2. If namePresent is true, then
      1. Let name be ? Get(options, "name").
      2. Set nameStr to ? ToString(name).
    3. Set defaultValue to ? Get(options, "defaultValue").
  5. Let asyncVariable be ? OrdinaryCreateFromConstructor(NewTarget, "%AsyncContext.Variable.prototype%", « [[AsyncVariableName]], [[AsyncVariableDefaultValue]] »).
  6. Set asyncVariable.[[AsyncVariableName]] to nameStr.
  7. Set asyncVariable.[[AsyncVariableDefaultValue]] to defaultValue.
  8. Return asyncVariable.

4.6.2 Properties of the AsyncContext.Variable Constructor

The AsyncContext.Variable constructor:

  • has a [[Prototype]] internal slot whose value is %Function.prototype%.
  • has the following properties:

4.6.2.1 AsyncContext.Variable.prototype

The initial value of AsyncContext.Variable.prototype is the AsyncContext.Variable prototype object.

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.

4.6.3 Properties of the AsyncContext.Variable Prototype Object

The AsyncContext.Variable prototype object:

  • is %AsyncContext.Variable.prototype%.
  • has a [[Prototype]] internal slot whose value is %Object.prototype%.
  • is an ordinary object.
  • does not have any of the other internal slots of AsyncContext.Variable instances.

4.6.3.1 AsyncContext.Variable.prototype.constructor

The initial value of AsyncContext.Variable.prototype.constructor is %AsyncContext.Variable%.

4.6.3.2 AsyncContext.Variable.prototype.run ( value, func, ...args )

This method performs the following steps when called:

  1. Let asyncVariable be the this value.
  2. Perform ? RequireInternalSlot(asyncVariable, [[AsyncVariableName]]).
  3. Let previousContextMapping be AsyncContextSnapshot().
  4. Let asyncContextMapping be a new empty List.
  5. For each Async Context Mapping Record p of previousContextMapping, do
    1. If SameValueZero(p.[[AsyncContextKey]], asyncVariable) is false, then
      1. Let q be the Async Context Mapping Record { [[AsyncContextKey]]: p.[[AsyncContextKey]], [[AsyncContextValue]]: p.[[AsyncContextValue]] }.
      2. Append q to asyncContextMapping.
  6. Assert: asyncContextMapping does not contain an Async Context Mapping Record whose [[AsyncContextKey]] is asyncVariable.
  7. Let p be the Async Context Mapping Record { [[AsyncContextKey]]: asyncVariable, [[AsyncContextValue]]: value }.
  8. Append p to asyncContextMapping.
  9. AsyncContextSwap(asyncContextMapping).
  10. Let result be Completion(Call(func, undefined, args)).
  11. AsyncContextSwap(previousContextMapping).
  12. Return result.

4.6.3.3 get AsyncContext.Variable.prototype.name

AsyncContext.Variable.prototype.name is an accessor property whose set accessor function is undefined. Its get accessor function performs the following steps when called:

  1. Let asyncVariable be the this value.
  2. Perform ? RequireInternalSlot(asyncVariable, [[AsyncVariableName]]).
  3. Return asyncVariable.[[AsyncVariableName]].

4.6.3.4 AsyncContext.Variable.prototype.get ( )

This method performs the following steps when called:

  1. Let asyncVariable be the this value.
  2. Perform ? RequireInternalSlot(asyncVariable, [[AsyncVariableDefaultValue]]).
  3. Let agentRecord be the surrounding agent's Agent Record.
  4. Let asyncContextMapping be agentRecord.[[AsyncContextMapping]].
  5. For each Async Context Mapping Record p of asyncContextMapping, do
    1. If SameValueZero(p.[[AsyncContextKey]], asyncVariable) is true, return p.[[AsyncContextValue]].
  6. Return asyncVariable.[[AsyncVariableDefaultValue]].

4.6.3.5 AsyncContext.Variable.prototype [ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "AsyncContext.Variable".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

4.6.4 Properties of AsyncContext.Variable Instances

AsyncContext.Variable instances are ordinary objects that inherit properties from the AsyncContext.Variable prototype object (the intrinsic, %AsyncContext.Variable.prototype%). AsyncContext.Variable instances are initially created with the internal slots described in Table 7.

Table 7: Internal Slots of AsyncContext.Variable Instances
Internal Slot Type Description
[[AsyncVariableName]] a String The name of the AsyncContext.Variable instance.
[[AsyncVariableDefaultValue]] an ECMAScript language value The default value of the AsyncContext.Variable instance when no entry is found in the mapping.

5 Managing Memory

5.1 FinalizationRegistry Objects

A FinalizationRegistry is an object that manages registration and unregistration of cleanup operations that are performed when target objects and symbols are garbage collected.

5.1.1 The FinalizationRegistry Constructor

The FinalizationRegistry constructor:

  • is %FinalizationRegistry%.
  • is the initial value of the "FinalizationRegistry" property of the global object.
  • creates and initializes a new FinalizationRegistry when called as a constructor.
  • is not intended to be called as a function and will throw an exception when called in that manner.
  • may be used as the value in an extends clause of a class definition. Subclass constructors that intend to inherit the specified FinalizationRegistry behaviour must include a super call to the FinalizationRegistry constructor to create and initialize the subclass instance with the internal state necessary to support the FinalizationRegistry.prototype built-in methods.

5.1.1.1 FinalizationRegistry ( cleanupCallback )

This function performs the following steps when called:

  1. If NewTarget is undefined, throw a TypeError exception.
  2. If IsCallable(cleanupCallback) is false, throw a TypeError exception.
  3. Let finalizationRegistry be ? OrdinaryCreateFromConstructor(NewTarget, "%FinalizationRegistry.prototype%", « [[Realm]], [[CleanupCallback]], [[Cells]], [[FinalizationRegistryAsyncContextSnapshot]] »).
  4. Let fn be the active function object.
  5. Set finalizationRegistry.[[Realm]] to fn.[[Realm]].
  6. Set finalizationRegistry.[[CleanupCallback]] to HostMakeJobCallback(cleanupCallback).
  7. Set finalizationRegistry.[[Cells]] to a new empty List.
  8. Set finalizationRegistry.[[FinalizationRegistryAsyncContextSnapshot]] to AsyncContextSnapshot().
  9. Return finalizationRegistry.

A Copyright & Software License

Copyright Notice

© 2024 Chengzhong Wu, Justin Ridgewell

Software License

All Software contained in this document ("Software") is protected by copyright and is being made available under the "BSD License", included below. This Software may be subject to third party rights (rights from parties other than Ecma International), including patent rights, and no licenses under such third party rights are granted under this license even if the third party concerned is a member of Ecma International. SEE THE ECMA CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT https://ecma-international.org/memento/codeofconduct.htm FOR INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.