Trim per-release overhead in the scene
Only re-measure the viewport at begin() when a container is mounted, and only allocate waiting machinery when an interrupted finish() actually needs to wait for a later release. Interrupted releases now resolve with the final decided outcome in every case. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Faarh2Ts6StJPcz2mRiHiR
This commit is contained in:
@@ -285,9 +285,12 @@ class Scene implements OriginScene {
|
|||||||
*/
|
*/
|
||||||
/** The latest release (finish call) of each operation. */
|
/** The latest release (finish call) of each operation. */
|
||||||
private readonly releases = new WeakMap<MutableOriginOperation, object>();
|
private readonly releases = new WeakMap<MutableOriginOperation, object>();
|
||||||
private readonly outcomes = new WeakMap<
|
/** Final outcome of each operation, once a release has decided it. */
|
||||||
|
private readonly outcomes = new WeakMap<MutableOriginOperation, boolean>();
|
||||||
|
/** Interrupted releases waiting for a later release to decide. */
|
||||||
|
private readonly waiters = new WeakMap<
|
||||||
MutableOriginOperation,
|
MutableOriginOperation,
|
||||||
{ promise: Promise<boolean>; resolve(committed: boolean): void }
|
Array<(committed: boolean) => void>
|
||||||
>();
|
>();
|
||||||
private readonly effectSets = new WeakMap<
|
private readonly effectSets = new WeakMap<
|
||||||
MutableOriginOperation,
|
MutableOriginOperation,
|
||||||
@@ -322,7 +325,7 @@ class Scene implements OriginScene {
|
|||||||
originKey: string,
|
originKey: string,
|
||||||
action: OriginAction,
|
action: OriginAction,
|
||||||
): Promise<OriginOperationHandle> {
|
): Promise<OriginOperationHandle> {
|
||||||
this.refreshViewport();
|
if (this.container) this.refreshViewport();
|
||||||
const operation = this.graph.begin(
|
const operation = this.graph.begin(
|
||||||
originKey,
|
originKey,
|
||||||
action,
|
action,
|
||||||
@@ -383,36 +386,40 @@ class Scene implements OriginScene {
|
|||||||
current,
|
current,
|
||||||
);
|
);
|
||||||
|
|
||||||
const outcome = this.outcomeOf(operation);
|
// Another release already decided this operation.
|
||||||
|
const decided = this.outcomes.get(operation);
|
||||||
|
if (decided !== undefined) return decided;
|
||||||
// A later operation may already have finalized this edge.
|
// A later operation may already have finalized this edge.
|
||||||
const finished = (operation.phase as OriginOperationPhase) === "finished";
|
const finished = (operation.phase as OriginOperationPhase) === "finished";
|
||||||
if (!this.graph.operation(operation.id) || finished) {
|
if (!this.graph.operation(operation.id) || finished)
|
||||||
const committed = this.graph.operation(operation.id)
|
return this.decide(
|
||||||
? operation.intent === "commit"
|
operation,
|
||||||
: commit;
|
finished ? operation.intent === "commit" : commit,
|
||||||
outcome.resolve(committed);
|
);
|
||||||
return committed;
|
// Caught by update() or superseded by a later finish(): wait for the
|
||||||
}
|
// release that decides.
|
||||||
// Caught by update() or superseded by a later finish().
|
if (!current())
|
||||||
if (!current()) return outcome.promise;
|
return new Promise<boolean>((resolve) =>
|
||||||
|
this.waiters.set(operation, [
|
||||||
|
...(this.waiters.get(operation) ?? []),
|
||||||
|
resolve,
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
|
||||||
const committed = commit
|
return this.decide(
|
||||||
|
operation,
|
||||||
|
commit
|
||||||
? this.graph.commit(operation.id)
|
? this.graph.commit(operation.id)
|
||||||
: (this.graph.cancel(operation.id), false);
|
: (this.graph.cancel(operation.id), false),
|
||||||
outcome.resolve(committed);
|
);
|
||||||
return committed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Resolves with an operation's final outcome, whichever release decides. */
|
/** Record an operation's final outcome and settle interrupted releases. */
|
||||||
private outcomeOf(operation: MutableOriginOperation) {
|
private decide(operation: MutableOriginOperation, committed: boolean) {
|
||||||
let outcome = this.outcomes.get(operation);
|
this.outcomes.set(operation, committed);
|
||||||
if (!outcome) {
|
for (const resolve of this.waiters.get(operation) ?? []) resolve(committed);
|
||||||
let resolve!: (committed: boolean) => void;
|
this.waiters.delete(operation);
|
||||||
const promise = new Promise<boolean>((done) => (resolve = done));
|
return committed;
|
||||||
outcome = { promise, resolve };
|
|
||||||
this.outcomes.set(operation, outcome);
|
|
||||||
}
|
|
||||||
return outcome;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
registerElement(nodeKey: string, element: HTMLElement | null): void {
|
registerElement(nodeKey: string, element: HTMLElement | null): void {
|
||||||
|
|||||||
Reference in New Issue
Block a user