Scopes are ownership boundaries for cleanup callbacks, child scopes, and scope-local values. A scope can be made active with scope.run(...) and later disposed as one unit.
createScope() creates a scope. Without an explicit parent, it uses the current active scope as parent. Pass null to create an explicit root scope.
import { createScope, onDispose } from "@kayahr/scope";
const scope = createScope();
scope.run(() => {
const controller = new AbortController();
const timer = setInterval(() => {
// ...
}, 1000);
onDispose(() => controller.abort());
onDispose(() => clearInterval(timer));
});
// ...
scope.dispose();
createScope(scope => ...) is shorthand for creating a scope and immediately running a callback inside it. createScope(parent, scope => ...) does the same with an explicit parent.
scope.run(...) temporarily makes that scope the active scope. getActiveScope() returns the current active scope, and onDispose(...) registers cleanup on it.
Only the synchronous execution of scope.run(...) or createScope(scope => ...) belongs to the scope. Work created after an await is outside that scope. If the callback returns a promise, that promise is returned as-is and is not awaited.
createScope(parent) creates an explicit child scope.
import { createScope } from "@kayahr/scope";
const parent = createScope();
const child = createScope(parent);
child.onDispose(() => {
console.log("child cleanup");
});
parent.dispose();
Disposing a parent also disposes all of its current child scopes. Creating a child scope under an already disposed parent throws a ScopeError.
scope.onDispose(...) registers cleanup on one scope.onDispose(...) registers cleanup on the current active scope, if there is one.scope.onDispose(...) registration after disposal runs immediately.AggregateError.createScope(scope => ...) callback throws and cleanup also fails, the callback error is listed first in the aggregate failure.