An execution context is a specification device that tracks the evaluation of one chunk of code: a script, a module, eval code, or a function call. At any moment an agent has exactly one running execution context, the top of the execution context stack (what developers call the call stack).
Every context carries:
- Function: the function object being run (
nullfor a script or module). - Realm: the realm whose intrinsics (
Array,Object, …) and global the code uses. - ScriptOrModule: where the code came from.
- LexicalEnvironment: the Environment Record used to resolve identifiers. It changes as the code enters and leaves blocks.
- VariableEnvironment: the record that holds
vardeclarations; fixed for the context's lifetime. - Plus code evaluation state, enough to suspend and resume the code.
Lifecycle. A function call creates a context (PrepareForOrdinaryCall): a new Function Environment Record whose outer link is the function's [[Environment]], then the context is pushed and becomes the running one. Declarations are instantiated, the body runs, and on return the context is popped, making the caller's context current again. A script or module gets its context first, and the stack is empty when the event loop is idle, which is why timer and promise callbacks start on a fresh stack.
Not LIFO everywhere. Generator and async function contexts are suspended and resumed later, so the spec says transitions are "usually" last-in-first-out.
Two caveats worth saying aloud. Contexts are purely a specification mechanism: engines use real stack frames, registers, and heap-allocated environments however they like. And the call stack (who called whom) is different from the scope chain (where code was written).