@solidjs/signals 2.0.0-rc.17 → 2.0.0-rc.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dev-shared.js +296 -191
- package/dist/dev.attribution.js +16 -16
- package/dist/dev.js +527 -311
- package/dist/observe/core/async.js +148 -115
- package/dist/observe/core/constants.js +3 -1
- package/dist/observe/core/core.js +27 -27
- package/dist/observe/core/effect.js +29 -32
- package/dist/observe/core/graph.js +5 -5
- package/dist/observe/core/owner.js +7 -7
- package/dist/observe/core/scheduler.js +23 -12
- package/dist/observe/core/verdict.js +2 -2
- package/dist/observe/deferred.js +16 -13
- package/dist/observe/from.js +248 -0
- package/dist/observe/index.js +2 -0
- package/dist/observe/store/reconcile.js +137 -121
- package/dist/observe/store/store.js +595 -618
- package/dist/observe/store/target.js +1 -5
- package/dist/prod/core/async.js +209 -176
- package/dist/prod/core/constants.js +3 -1
- package/dist/prod/core/core.js +33 -33
- package/dist/prod/core/effect.js +24 -27
- package/dist/prod/core/graph.js +2 -2
- package/dist/prod/core/lanes.js +14 -14
- package/dist/prod/core/scheduler.js +35 -24
- package/dist/prod/core/truth.js +4 -4
- package/dist/prod/core/verdict.js +7 -7
- package/dist/prod/deferred.js +17 -14
- package/dist/prod/from.js +248 -0
- package/dist/prod/index.js +2 -0
- package/dist/prod/store/optimistic.js +1 -1
- package/dist/prod/store/reconcile.js +137 -121
- package/dist/prod/store/store.js +94 -117
- package/dist/prod/store/target.js +13 -17
- package/dist/types/core/async.d.ts +12 -2
- package/dist/types/core/constants.d.ts +5 -0
- package/dist/types/core/core.d.ts +19 -3
- package/dist/types/core/scheduler.d.ts +15 -3
- package/dist/types/from.d.ts +47 -0
- package/dist/types/index.d.ts +1 -0
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { notifyStatus, releaseFlightTeardown, handleAsync, clearStatus, parkLoadingWindow, stageError, settlePendingSource, releaseIfSettledUnobserved, settleErroredDependents } from "./async.js";
|
|
2
2
|
|
|
3
|
-
import { STATUS_UNINITIALIZED, REACTIVE_LAZY, REACTIVE_NONE, defaultContext, CONFIG_TRANSPARENT, CONFIG_OWNED_WRITE, CONFIG_AUTO_DISPOSE, CONFIG_SYNC, CONFIG_NO_SNAPSHOT, CONFIG_PLUMBING, CONFIG_IN_SNAPSHOT_SCOPE, NOT_PENDING, NO_SNAPSHOT, CONFIG_HAS_SNAPSHOT, CONFIG_HELD, REACTIVE_MANUAL_WRITE, STATUS_ERROR, REACTIVE_DIRTY, CONFIG_OVERRIDE, REACTIVE_DISPOSED, REACTIVE_CHECK, REACTIVE_IN_HEAP, REACTIVE_REASK, REACTIVE_SNAPSHOT_STALE, CONFIG_CHILDREN_FORBIDDEN, CONFIG_VERDICT, STATUS_PENDING, REACTIVE_LANE_DIRTY, CONFIG_GUESS, REACTIVE_RECOMPUTING_DEPS, CONFIG_LAGS, EFFECT_RENDER, CONFIG_HELD_FRAME, EFFECT_TRACKED, CONFIG_STAGED, CONFIG_STAGED_ERROR, REACTIVE_ZOMBIE, REACTIVE_MISSED_WAKE, REACTIVE_JOINED, REACTIVE_STAGED_READ, REACTIVE_PROBED, REACTIVE_FRAME_READ, REACTIVE_LANE_READ, REACTIVE_SCREEN_READ, REACTIVE_PROBE_UNANSWERED, CAUGHT_REARMED, CONFIG_PROMOTED, CONFIG_INPUTS_PUBLISHED, CONFIG_FRESH_READ, REACTIVE_IN_HEAP_HEIGHT, CONFIG_SLOT_NODE, EFFECT_USER, STATUS_NONE } from "./constants.js";
|
|
3
|
+
import { STATUS_UNINITIALIZED, REACTIVE_LAZY, REACTIVE_NONE, defaultContext, CONFIG_TRANSPARENT, CONFIG_OWNED_WRITE, CONFIG_AUTO_DISPOSE, CONFIG_SYNC, CONFIG_NO_SNAPSHOT, CONFIG_PLUMBING, CONFIG_IN_SNAPSHOT_SCOPE, NOT_PENDING, NO_SNAPSHOT, CONFIG_HAS_SNAPSHOT, CONFIG_HELD, REACTIVE_MANUAL_WRITE, STATUS_ERROR, REACTIVE_DIRTY, CONFIG_OVERRIDE, REACTIVE_DISPOSED, REACTIVE_CHECK, REACTIVE_IN_HEAP, REACTIVE_REASK, REACTIVE_SNAPSHOT_STALE, CONFIG_CHILDREN_FORBIDDEN, CONFIG_VERDICT, STATUS_PENDING, REACTIVE_LANE_DIRTY, CONFIG_GUESS, REACTIVE_RECOMPUTING_DEPS, CONFIG_LAGS, EFFECT_RENDER, CONFIG_HELD_FRAME, EFFECT_TRACKED, CONFIG_STAGED, CONFIG_STAGED_ERROR, REACTIVE_ZOMBIE, REACTIVE_MISSED_WAKE, REACTIVE_JOINED, REACTIVE_STAGED_READ, REACTIVE_PROBED, REACTIVE_FRAME_READ, REACTIVE_LANE_READ, REACTIVE_SCREEN_READ, REACTIVE_PROBE_UNANSWERED, CAUGHT_REARMED, CONFIG_PROMOTED, CONFIG_INPUTS_PUBLISHED, CONFIG_FRESH_READ, REACTIVE_IN_HEAP_HEIGHT, CONFIG_SLOT_NODE, EFFECT_USER, NewSet, STATUS_NONE } from "./constants.js";
|
|
4
4
|
|
|
5
5
|
import { NotReadyError } from "./error.js";
|
|
6
6
|
|
|
@@ -82,7 +82,7 @@ function ownerInSnapshotScope(e) {
|
|
|
82
82
|
|
|
83
83
|
function setSnapshotCapture(e) {
|
|
84
84
|
snapshotCaptureActive = e;
|
|
85
|
-
if (e && !snapshotSources) snapshotSources = new
|
|
85
|
+
if (e && !snapshotSources) snapshotSources = new NewSet;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
function markSnapshotScope(e) {
|
|
@@ -243,14 +243,14 @@ function recompute(e, t = false) {
|
|
|
243
243
|
// value, leaving blocked dependents outside that source’s settle walk.
|
|
244
244
|
const u = e.m & STATUS_ERROR ? e.T?.F : undefined;
|
|
245
245
|
const a = (e.m & STATUS_PENDING) !== 0;
|
|
246
|
-
const _ = a ? e.T?.
|
|
246
|
+
const _ = a ? e.T?.se : undefined;
|
|
247
247
|
// Pending SOURCE-hood, captured before the compute clears status: a node
|
|
248
248
|
// whose own flight parked dependents self-registers in _pendingSources
|
|
249
249
|
// (notifyStatus, isSource). If this recompute supersedes that flight and
|
|
250
250
|
// settles synchronously, those dependents settle HERE — asyncWrite's
|
|
251
251
|
// settlePendingSource walk never runs for a landing that was preempted
|
|
252
252
|
// (#3181).
|
|
253
|
-
const I = e.T?.
|
|
253
|
+
const I = e.T?.se?.has(e);
|
|
254
254
|
// D-41: this pass's error is staged, not published (`stageError`).
|
|
255
255
|
let N = false;
|
|
256
256
|
// A19 exc. 2: a `refresh()` re-asks the question already answered — quiet
|
|
@@ -275,7 +275,7 @@ function recompute(e, t = false) {
|
|
|
275
275
|
// L2: did this pass read the future (REACTIVE_JOINED, set by read) — or,
|
|
276
276
|
// a lane's mount, a staging of this flush (#3851, #4166)?
|
|
277
277
|
let R = false;
|
|
278
|
-
let
|
|
278
|
+
let C = tracking;
|
|
279
279
|
tracking = true;
|
|
280
280
|
try {
|
|
281
281
|
if (!false && e.l & CONFIG_SYNC) {
|
|
@@ -319,7 +319,7 @@ function recompute(e, t = false) {
|
|
|
319
319
|
// D-41: a pass of a held node, or one that read a staging of this
|
|
320
320
|
// flush, stages its error (`stageError`).
|
|
321
321
|
if (n || !(N = stageError(e, t, true))) {
|
|
322
|
-
if (n) ext(e).
|
|
322
|
+
if (n) ext(e).fe = true;
|
|
323
323
|
notifyStatus(e, n ? STATUS_PENDING : STATUS_ERROR, t);
|
|
324
324
|
// The replacement source is fully propagated now. If no new flight
|
|
325
325
|
// re-owned self, retire the superseded flight and its dependent copies.
|
|
@@ -334,10 +334,10 @@ function recompute(e, t = false) {
|
|
|
334
334
|
// re-park twin of the unchanged-value recovery sweep below; dependents
|
|
335
335
|
// with another path keep the source (retryReaches). A staged error
|
|
336
336
|
// answered what the pass carried: the same.
|
|
337
|
-
if ((n || N) && _) for (const t of _) if (t !== e && !e.T?.
|
|
337
|
+
if ((n || N) && _) for (const t of _) if (t !== e && !e.T?.se?.has(t)) settlePendingSource(e, t);
|
|
338
338
|
}
|
|
339
339
|
} finally {
|
|
340
|
-
tracking =
|
|
340
|
+
tracking = C;
|
|
341
341
|
if (laneStageHook) laneRoot = E;
|
|
342
342
|
// Consume the missed-wake latch (#3037, set by insertSubs): a dep write
|
|
343
343
|
// landed beneath this pass on a link it had already validated. The wipe
|
|
@@ -391,12 +391,12 @@ function recompute(e, t = false) {
|
|
|
391
391
|
// seat that read none of the lane's world has left it: its result is the
|
|
392
392
|
// frame's (a derivation whose branch no longer reaches the guess). A
|
|
393
393
|
// guess is written, not derived — it never leaves this way.
|
|
394
|
-
let
|
|
394
|
+
let d = !laneStageHook ? null : passLane;
|
|
395
395
|
// Listed before its staging, a pending pass included (the lane's own
|
|
396
396
|
// flight is the lane's); false: the pass left the lane (lanes.ts).
|
|
397
397
|
const O = !!e.T?.F || N;
|
|
398
|
-
if (laneStageHook &&
|
|
399
|
-
if (laneStageHook(e,
|
|
398
|
+
if (laneStageHook && d !== null) {
|
|
399
|
+
if (laneStageHook(e, d, t, O)) setPassLane(d); else d = null;
|
|
400
400
|
}
|
|
401
401
|
if (!O) {
|
|
402
402
|
// Observe-tier fan-in (HUGE_FAN_IN): the validated prefix [_deps.._depsTail]
|
|
@@ -445,7 +445,7 @@ function recompute(e, t = false) {
|
|
|
445
445
|
// Lane work's run is the lane's (released at its reveal) — a first
|
|
446
446
|
// pass under a lane too: `effect()` skips the synchronous first run of
|
|
447
447
|
// a lane's node.
|
|
448
|
-
if (!t ||
|
|
448
|
+
if (!t || d !== null) globalQueue.enqueue(n, e.W ??= GlobalQueue.K.bind(null, e), d);
|
|
449
449
|
}
|
|
450
450
|
// Lanes. A written guess's own pass from the frame: its source
|
|
451
451
|
// recomputed it — the truth (A18: "the source is whatever recomputes the
|
|
@@ -453,7 +453,7 @@ function recompute(e, t = false) {
|
|
|
453
453
|
// confirm is a landing too — the lane's end commits it) and notifies
|
|
454
454
|
// only a correction: an equal truth re-runs nothing (lanes.ts). (As the
|
|
455
455
|
// lane's own work the lane judged it — `laneStage`.)
|
|
456
|
-
if (!t &&
|
|
456
|
+
if (!t && d === null && e.l & CONFIG_GUESS && laneOutcomeHook(e, S, O)) ; else if (O) ; else if (s) {
|
|
457
457
|
// L2: a first pass is born held — staged, committed with the
|
|
458
458
|
// transaction, its effect's first run the landing's (A29; `effect()`
|
|
459
459
|
// skips the synchronous first run on a staged value) — when the flush
|
|
@@ -470,14 +470,14 @@ function recompute(e, t = false) {
|
|
|
470
470
|
// pass that runs before anything joins: the pass's input, not a verdict
|
|
471
471
|
// after it. An effect still carrying an uncommitted staged value
|
|
472
472
|
// re-stages: the commit applies the latest pass, not the born-held one.
|
|
473
|
-
if (
|
|
473
|
+
if (d !== null) {
|
|
474
474
|
// Lane work: the lane's value — into the slot while the lane has not
|
|
475
475
|
// revealed (its reveal shows it), as its staging once it has (the
|
|
476
476
|
// next reveal promotes it; the screen keeps the revealed value). An
|
|
477
477
|
// effect's value slot is private: the run the lane holds is what
|
|
478
478
|
// shows it — unless the effect was born held, whose first run is the
|
|
479
479
|
// commit's (A29): it re-stages, as below.
|
|
480
|
-
if (n && e.ue === NOT_PENDING) e.Ie = S; else if (n ||
|
|
480
|
+
if (n && e.ue === NOT_PENDING) e.Ie = S; else if (n || d.It) e.ue = S; else e.T.V = S;
|
|
481
481
|
} else if (t ? !((flushTransaction !== null || passTx !== null) && (R || creatorPass(T)?.R & REACTIVE_JOINED)) : n && e.ue === NOT_PENDING) {
|
|
482
482
|
// A first pass publishes directly. So does an effect: its value slot
|
|
483
483
|
// is private (only its own run reads it), and the staging round-trip
|
|
@@ -517,7 +517,7 @@ function recompute(e, t = false) {
|
|
|
517
517
|
if (e.o !== null) {
|
|
518
518
|
insertSubs(e);
|
|
519
519
|
// Lane work re-staged: the lane's members re-derive as its work.
|
|
520
|
-
if (
|
|
520
|
+
if (d !== null) laneDirty(e, d);
|
|
521
521
|
}
|
|
522
522
|
} else if (e.Et != c) {
|
|
523
523
|
for (let t = e.o; t !== null; t = t.t) insertIntoHeapHeight(t.u, dirtyQueue);
|
|
@@ -546,7 +546,7 @@ function recompute(e, t = false) {
|
|
|
546
546
|
// hold's commit (D-12) — but the hold does not wait for it: its only
|
|
547
547
|
// readers are behind the fallback (`_hidden`; F-4, #3540). A boundary
|
|
548
548
|
// re-armed by `on` owns what it collects outright (D-14): not held.
|
|
549
|
-
if (t &&
|
|
549
|
+
if (t && d === null && R && e.m & STATUS_PENDING) {
|
|
550
550
|
const t = flushTransaction ?? passTx;
|
|
551
551
|
if (t && !t.V && freshHook?.(e) !== CAUGHT_REARMED) holdNode(e, t);
|
|
552
552
|
}
|
|
@@ -572,7 +572,7 @@ function recompute(e, t = false) {
|
|
|
572
572
|
}
|
|
573
573
|
// Observe: the posture the run executed under — lane work (optimistic:
|
|
574
574
|
// overlay, never waste), a transaction's pass (held), or plain.
|
|
575
|
-
if (attrHooks !== null) attrHooks.recomputeEnd(e, t, i,
|
|
575
|
+
if (attrHooks !== null) attrHooks.recomputeEnd(e, t, i, d !== null, flushTransaction !== null || passTx !== null || (e.l & CONFIG_HELD) !== 0, e.ue !== NOT_PENDING);
|
|
576
576
|
// A staged value, a parked frame (L2: the commit retires it), or status the
|
|
577
577
|
// commit sweep must settle (a pending or uninitialized pass), queues the
|
|
578
578
|
// node for this flush's commit. A first pass queues only when pending or
|
|
@@ -581,7 +581,7 @@ function recompute(e, t = false) {
|
|
|
581
581
|
if (e.ue !== NOT_PENDING || e.T !== null && (e.T.Nt !== null || e.T.ft !== null) || (e.m & (STATUS_PENDING | STATUS_UNINITIALIZED)) !== 0 && (!t || (e.m & STATUS_PENDING) !== 0)) {
|
|
582
582
|
e.l |= CONFIG_STAGED;
|
|
583
583
|
// Lane work is the lane's to reveal (its seam), not this flush's commit.
|
|
584
|
-
if (
|
|
584
|
+
if (d === null) queuePendingNode(e);
|
|
585
585
|
}
|
|
586
586
|
setPassLane(s);
|
|
587
587
|
// Missed-wake reschedule (see the finally above): values this pass read
|
|
@@ -661,10 +661,10 @@ function computed(e, t) {
|
|
|
661
661
|
_: null,
|
|
662
662
|
Ne: 0,
|
|
663
663
|
o: null,
|
|
664
|
-
|
|
664
|
+
Ct: null,
|
|
665
665
|
_parent: context,
|
|
666
666
|
Xe: null,
|
|
667
|
-
|
|
667
|
+
dt: null,
|
|
668
668
|
ze: null,
|
|
669
669
|
R: t?.lazy ? REACTIVE_LAZY : REACTIVE_NONE,
|
|
670
670
|
m: o ? 0 : STATUS_UNINITIALIZED,
|
|
@@ -694,8 +694,8 @@ function computed(e, t) {
|
|
|
694
694
|
Se: null,
|
|
695
695
|
ae: null,
|
|
696
696
|
F: undefined,
|
|
697
|
-
se: undefined,
|
|
698
697
|
fe: undefined,
|
|
698
|
+
se: undefined,
|
|
699
699
|
Dt: undefined,
|
|
700
700
|
lt: undefined,
|
|
701
701
|
Nt: null,
|
|
@@ -838,10 +838,10 @@ function computed(e, t) {
|
|
|
838
838
|
_: null,
|
|
839
839
|
Ne: 0,
|
|
840
840
|
o: null,
|
|
841
|
-
|
|
841
|
+
Ct: null,
|
|
842
842
|
_parent: context,
|
|
843
843
|
Xe: null,
|
|
844
|
-
|
|
844
|
+
dt: null,
|
|
845
845
|
ze: null,
|
|
846
846
|
R: REACTIVE_LAZY,
|
|
847
847
|
m: STATUS_UNINITIALIZED,
|
|
@@ -886,7 +886,7 @@ function setEffectStatusNotify(e) {
|
|
|
886
886
|
* 0, and only effect literals carry the field) get the shared notifier.
|
|
887
887
|
* Presence doubles as the "display consumer" membership test in the status
|
|
888
888
|
* walks, exactly as the per-node field did when every effect carried one. */ function statusNotifierOf(e) {
|
|
889
|
-
return e.i ? effectStatusNotify
|
|
889
|
+
return e.i ? effectStatusNotify : null;
|
|
890
890
|
}
|
|
891
891
|
|
|
892
892
|
const lazyOptions = {
|
|
@@ -919,7 +919,7 @@ function signal(e, t) {
|
|
|
919
919
|
l: (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (t?.le ? CONFIG_NO_SNAPSHOT : 0),
|
|
920
920
|
Ie: e,
|
|
921
921
|
o: null,
|
|
922
|
-
|
|
922
|
+
Ct: null,
|
|
923
923
|
ie: clock,
|
|
924
924
|
ue: NOT_PENDING,
|
|
925
925
|
Ot: -1,
|
|
@@ -957,7 +957,7 @@ function isEqual(e, t) {
|
|
|
957
957
|
l: CONFIG_OWNED_WRITE | CONFIG_SLOT_NODE,
|
|
958
958
|
Ie: e,
|
|
959
959
|
o: null,
|
|
960
|
-
|
|
960
|
+
Ct: null,
|
|
961
961
|
ie: clock,
|
|
962
962
|
ue: NOT_PENDING,
|
|
963
963
|
Ot: -1,
|
|
@@ -18,45 +18,48 @@ import { globalQueue, schedule, heldRunHook, haltReactivity, GlobalQueue } from
|
|
|
18
18
|
* Effects are the leaf nodes of our reactive graph. When their sources change, they are
|
|
19
19
|
* automatically added to the queue of effects to re-execute, which will cause them to fetch their
|
|
20
20
|
* sources and recompute
|
|
21
|
-
*/ function effect(t, e, o,
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
recompute(
|
|
21
|
+
*/ function effect(t, e, o, r) {
|
|
22
|
+
const u = !!r?.user;
|
|
23
|
+
const E = createEffectNode(t, e, o, u ? EFFECT_USER : EFFECT_RENDER, r);
|
|
24
|
+
recompute(E, true);
|
|
25
25
|
// A first pass that read a staged value was staged itself (recompute: born
|
|
26
26
|
// staged); the flush's commit replays this effect. Its first run is not this
|
|
27
27
|
// creation's (A29). A lane's node likewise: its run is the lane's, queued
|
|
28
28
|
// by the pass and released at the reveal (lanes.ts).
|
|
29
|
-
!
|
|
29
|
+
!r?.defer && E.ue === NOT_PENDING && !E.T?.Je?.V && (E.i === EFFECT_USER || r?.schedule ? globalQueue.enqueue(E.i, runEffect.bind(null, E)) : runEffect(E, E.i));
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
function notifyEffectStatus(
|
|
33
|
-
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
if (o & STATUS_ERROR) {
|
|
32
|
+
function notifyEffectStatus() {
|
|
33
|
+
const t = this.m;
|
|
34
|
+
const e = this.T?.F;
|
|
35
|
+
if (t & STATUS_ERROR) {
|
|
37
36
|
globalQueue.notify(this, STATUS_PENDING, 0);
|
|
38
37
|
if (this.i === EFFECT_USER) {
|
|
39
38
|
// The error handler is the error arm of the effect phase (#2840 ruling):
|
|
40
39
|
// queue it like the effect function. It runs in the same imperative,
|
|
41
40
|
// writable scope and throws escalate the same way. No payload is queued — the node already carries `_statusFlags`/`_error`,
|
|
42
41
|
// and the runner dispatches on them, so a recovery before the effect
|
|
43
|
-
// phase takes the success arm instead.
|
|
44
|
-
//
|
|
45
|
-
// re-propagates unblocked at commit.
|
|
42
|
+
// phase takes the success arm instead. (Re-read: the boundary
|
|
43
|
+
// notify above can run a redraw.)
|
|
46
44
|
if (this.m & STATUS_ERROR) {
|
|
47
45
|
this.Qe = true;
|
|
48
46
|
globalQueue.enqueue(this.i, this.W ??= runEffect.bind(null, this));
|
|
49
47
|
}
|
|
50
48
|
return;
|
|
51
49
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
haltReactivity(unwrapStatusError(u));
|
|
56
|
-
throw u;
|
|
57
|
-
}
|
|
50
|
+
// Dev locates the halt at the node that threw: the StatusError's
|
|
51
|
+
// source, upstream of this effect when a computed failed.
|
|
52
|
+
escalate(this, unwrapStatusError(e), e, this);
|
|
58
53
|
} else if (this.i === EFFECT_RENDER) {
|
|
59
|
-
globalQueue.notify(this, STATUS_PENDING | STATUS_ERROR,
|
|
54
|
+
globalQueue.notify(this, STATUS_PENDING | STATUS_ERROR, t, e);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** An effect's error no boundary takes halts the system (boundary-or-halt):
|
|
59
|
+
* halted with `cause`, `thrown` rethrown; dev locates it at `subject`. */ function escalate(t, e, o = e, r = t) {
|
|
60
|
+
if (!globalQueue.notify(t, STATUS_ERROR, STATUS_ERROR)) {
|
|
61
|
+
haltReactivity(e);
|
|
62
|
+
throw o;
|
|
60
63
|
}
|
|
61
64
|
}
|
|
62
65
|
|
|
@@ -92,10 +95,7 @@ function runEffect(t, e) {
|
|
|
92
95
|
e?.();
|
|
93
96
|
}) : console.error(e);
|
|
94
97
|
} catch (e) {
|
|
95
|
-
|
|
96
|
-
haltReactivity(e);
|
|
97
|
-
throw e;
|
|
98
|
-
}
|
|
98
|
+
escalate(t, e);
|
|
99
99
|
}
|
|
100
100
|
return;
|
|
101
101
|
}
|
|
@@ -107,10 +107,10 @@ function runEffect(t, e) {
|
|
|
107
107
|
// cascade an observer reports) and what times the callback (the `effect`
|
|
108
108
|
// record) — facts a production observer needs, not only a dev console.
|
|
109
109
|
if (attrHooks !== null) attrHooks.effectRunStart(t);
|
|
110
|
-
const
|
|
110
|
+
const r = t.kt;
|
|
111
111
|
t.kt = undefined;
|
|
112
112
|
try {
|
|
113
|
-
|
|
113
|
+
r?.();
|
|
114
114
|
const e = t.Ge(t.Ie, t._t);
|
|
115
115
|
if (false && e !== undefined && typeof e !== "function") ;
|
|
116
116
|
// The final cleanup is invoked by disposeChildren at true disposal.
|
|
@@ -118,10 +118,7 @@ function runEffect(t, e) {
|
|
|
118
118
|
} catch (e) {
|
|
119
119
|
ext(t).F = new StatusError(t, e);
|
|
120
120
|
t.m |= STATUS_ERROR;
|
|
121
|
-
|
|
122
|
-
haltReactivity(e);
|
|
123
|
-
throw e;
|
|
124
|
-
}
|
|
121
|
+
escalate(t, e);
|
|
125
122
|
} finally {
|
|
126
123
|
t._t = t.Ie;
|
|
127
124
|
t.Qe = false;
|
|
@@ -159,8 +156,8 @@ GlobalQueue.K = runEffect;
|
|
|
159
156
|
const e = o.kt;
|
|
160
157
|
o.kt = undefined;
|
|
161
158
|
e?.();
|
|
162
|
-
const
|
|
163
|
-
o.kt =
|
|
159
|
+
const r = staleValues(t);
|
|
160
|
+
o.kt = r;
|
|
164
161
|
}, {
|
|
165
162
|
...e,
|
|
166
163
|
lazy: true
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { REACTIVE_RECOMPUTING_DEPS, CONFIG_AUTO_DISPOSE, STATUS_PENDING, REACTIVE_DISPOSED, REACTIVE_ZOMBIE, CONFIG_SLOT_NODE } from "./constants.js";
|
|
1
|
+
import { NewSet, REACTIVE_RECOMPUTING_DEPS, CONFIG_AUTO_DISPOSE, STATUS_PENDING, REACTIVE_DISPOSED, REACTIVE_ZOMBIE, CONFIG_SLOT_NODE } from "./constants.js";
|
|
2
2
|
|
|
3
3
|
import { deleteFromHeap } from "./heap.js";
|
|
4
4
|
|
|
@@ -21,7 +21,7 @@ function unlinkSubs(e) {
|
|
|
21
21
|
const l = e.G;
|
|
22
22
|
const o = e.t;
|
|
23
23
|
const s = e.en;
|
|
24
|
-
if (o !== null) o.en = s; else n.
|
|
24
|
+
if (o !== null) o.en = s; else n.Ct = s;
|
|
25
25
|
if (s !== null) s.t = o; else {
|
|
26
26
|
n.o = o;
|
|
27
27
|
if (o === null) {
|
|
@@ -107,7 +107,7 @@ function unobserved(e) {
|
|
|
107
107
|
* stays alive and serves its cache, uniform with observed memos) while
|
|
108
108
|
* reclamation still happens within one microtask — the enqueue site arms
|
|
109
109
|
* schedule(), so a flush is guaranteed even when no other work is queued.
|
|
110
|
-
*/ const dormantNodes = new
|
|
110
|
+
*/ const dormantNodes = new NewSet;
|
|
111
111
|
|
|
112
112
|
function sweepDormant() {
|
|
113
113
|
if (dormantNodes.size === 0) return;
|
|
@@ -143,9 +143,9 @@ function link(e, n) {
|
|
|
143
143
|
// [deps.._depsTail] prefix — the O(1) equivalent of scanning the dep list
|
|
144
144
|
// (the old alien-signals `isValidLink` walk, O(n²) when a computation
|
|
145
145
|
// re-reads earlier deps non-consecutively, e.g. store leaf reads).
|
|
146
|
-
const r = e.
|
|
146
|
+
const r = e.Ct;
|
|
147
147
|
if (r !== null && r.u === n && (!s || r.Te === n.Ne)) return;
|
|
148
|
-
const t = n._ = e.
|
|
148
|
+
const t = n._ = e.Ct = {
|
|
149
149
|
S: e,
|
|
150
150
|
u: n,
|
|
151
151
|
G: o,
|
|
@@ -107,7 +107,7 @@ function disposeChildren(e, n = false, r) {
|
|
|
107
107
|
// on the fresh head and survives. Pointing each drained child's prev at
|
|
108
108
|
// itself routes its later splice onto the detached chain, never the head,
|
|
109
109
|
// and keeps the dev owner-chain-head invariant honest for those children.
|
|
110
|
-
l.
|
|
110
|
+
l.dt = l;
|
|
111
111
|
disposeChildren(l, true);
|
|
112
112
|
// Read after, not before: a sibling this disposal made dormant spliced
|
|
113
113
|
// itself out of the detached chain, and a cleanup may then have linked
|
|
@@ -122,11 +122,11 @@ function disposeChildren(e, n = false, r) {
|
|
|
122
122
|
// node._nextSibling intact so outer walks that already advanced past us
|
|
123
123
|
// still reach later siblings.
|
|
124
124
|
if (n && !r && !(t & REACTIVE_ZOMBIE) && e._parent !== null && !(e._parent.R & REACTIVE_DISPOSED)) {
|
|
125
|
-
const n = e.
|
|
125
|
+
const n = e.dt;
|
|
126
126
|
const r = e.Xe;
|
|
127
127
|
if (n !== null) n.Xe = r; else e._parent.ze = r;
|
|
128
|
-
if (r !== null) r.
|
|
129
|
-
e.
|
|
128
|
+
if (r !== null) r.dt = n;
|
|
129
|
+
e.dt = null;
|
|
130
130
|
}
|
|
131
131
|
runDisposal(e, r);
|
|
132
132
|
// Final effect-returned cleanup fires at true disposal, after `_disposal`
|
|
@@ -140,9 +140,9 @@ function disposeChildren(e, n = false, r) {
|
|
|
140
140
|
|
|
141
141
|
function linkChild(e, n) {
|
|
142
142
|
const r = e.ze;
|
|
143
|
-
n.
|
|
143
|
+
n.dt = null;
|
|
144
144
|
n.Xe = r;
|
|
145
|
-
if (r !== null) r.
|
|
145
|
+
if (r !== null) r.dt = n;
|
|
146
146
|
e.ze = n;
|
|
147
147
|
}
|
|
148
148
|
|
|
@@ -311,7 +311,7 @@ function disposeRootSelf(e = true) {
|
|
|
311
311
|
Ht: n?.Pt ? n.Ht : n,
|
|
312
312
|
ze: null,
|
|
313
313
|
Xe: null,
|
|
314
|
-
|
|
314
|
+
dt: null,
|
|
315
315
|
rt: null,
|
|
316
316
|
A: n?.A || defaultContext,
|
|
317
317
|
ct: 0,
|
|
@@ -291,7 +291,7 @@ let judge = null;
|
|
|
291
291
|
/** A source the pending node waits on that is `t`'s (held by it, or by no
|
|
292
292
|
* one) — not another transaction's or lane's work. Itself, when it is the
|
|
293
293
|
* source. */ function ownSource(e, o) {
|
|
294
|
-
const n = e.T?.
|
|
294
|
+
const n = e.T?.se;
|
|
295
295
|
if (n === undefined) return true;
|
|
296
296
|
for (const e of n) {
|
|
297
297
|
const n = e.T?.Je;
|
|
@@ -819,31 +819,34 @@ class GlobalQueue {
|
|
|
819
819
|
* or without the held read) owes nothing. A run this transaction stashed
|
|
820
820
|
* for it is void (#3322: an effect has one value slot, and the stale pass
|
|
821
821
|
* overwrote the value that run was for) — the re-derivation's run replaces
|
|
822
|
-
* it. */ function reruns(e) {
|
|
823
|
-
|
|
824
|
-
|
|
822
|
+
* it. Truthy when an effect re-derives (`land`). */ function reruns(e) {
|
|
823
|
+
let o;
|
|
824
|
+
for (let n = 0; n < e.En.length; n++) {
|
|
825
|
+
const t = e.En[n];
|
|
825
826
|
// An errored reader's display is its error (D-39): the landing gives it
|
|
826
827
|
// nothing to re-derive, and a re-run would be a read that retries the
|
|
827
828
|
// errored source (#3945).
|
|
828
|
-
if (
|
|
829
|
-
if (
|
|
830
|
-
|
|
831
|
-
|
|
829
|
+
if (t.R & REACTIVE_DISPOSED || t.m & STATUS_ERROR) continue;
|
|
830
|
+
if (t.R & REACTIVE_FRAME_READ || t.l & CONFIG_VERDICT) {
|
|
831
|
+
o ||= t.i;
|
|
832
|
+
t.R &= ~REACTIVE_FRAME_READ;
|
|
833
|
+
t.Qe = false;
|
|
832
834
|
// Its frame is replaced by the re-derivation: a run one of its
|
|
833
835
|
// children queued this flush (re-run by the same landing) is for the
|
|
834
836
|
// frame being replaced — void too (#3404).
|
|
835
|
-
for (let e =
|
|
836
|
-
enqueueSub(
|
|
837
|
+
for (let e = t.ze; e !== null; e = e.Xe) if (e.i) e.Qe = false;
|
|
838
|
+
enqueueSub(t);
|
|
837
839
|
}
|
|
838
840
|
}
|
|
839
841
|
e.En.length = 0;
|
|
842
|
+
return o;
|
|
840
843
|
}
|
|
841
844
|
|
|
842
845
|
/** The landing: the held frame becomes the frame. */ function land(e) {
|
|
843
846
|
// Attribution hook: judged complete — its held writes commit next
|
|
844
847
|
// (`_nodes` still lists them).
|
|
845
848
|
if (attrHooks !== null) attrHooks.transitionSettled(e);
|
|
846
|
-
reruns(e);
|
|
849
|
+
const o = reruns(e);
|
|
847
850
|
if (e.I !== null) releaseMarksHook(e.I);
|
|
848
851
|
// Old children die in the commits (cleanups first), then the stashed
|
|
849
852
|
// effects run ahead of this flush's own. A node a lane took over since
|
|
@@ -858,7 +861,15 @@ class GlobalQueue {
|
|
|
858
861
|
// `u`, which has left `transactions`: the write is this landing's, and
|
|
859
862
|
// the next flush must not park in it (#4089).
|
|
860
863
|
if (flushTransaction === e) flushTransaction = null;
|
|
861
|
-
|
|
864
|
+
// An effect re-derives next round (`reruns`): the held runs wait for it
|
|
865
|
+
// (D-9, the A15 reveal corollary, #4071). Its re-derivation can discover a
|
|
866
|
+
// flight — a stale reader whose mainline pass stopped reading it, now
|
|
867
|
+
// reading the landed world — and a landing that showed its runs first
|
|
868
|
+
// would reveal the held write beside a frame that can only show its old
|
|
869
|
+
// value. Queued last in this effect phase, the release hands them to the
|
|
870
|
+
// next round's own runs, ahead of the re-derivation's: they show with it,
|
|
871
|
+
// or park with it in the hold its pending opens. The commits stand.
|
|
872
|
+
if (o) globalQueue.un[1].push(() => releaseQueues(e)); else releaseQueues(e);
|
|
862
873
|
}
|
|
863
874
|
|
|
864
875
|
/** The held runs join this flush's effect phase after its own runs (the
|
|
@@ -139,8 +139,8 @@ let probeFound = false;
|
|
|
139
139
|
* when every flight it waits on is. */ function quietPending(e) {
|
|
140
140
|
const t = e.T;
|
|
141
141
|
if (t === null) return false;
|
|
142
|
-
if (t.
|
|
143
|
-
for (const e of t.
|
|
142
|
+
if (t.se !== undefined) {
|
|
143
|
+
for (const e of t.se) if (!e.T?.ut) return false;
|
|
144
144
|
return true;
|
|
145
145
|
}
|
|
146
146
|
return t.ut;
|
package/dist/observe/deferred.js
CHANGED
|
@@ -135,26 +135,26 @@ GlobalQueue.er = e => lagging.size !== 0 ? lagOf(e, new Set) : undefined;
|
|
|
135
135
|
// Sticky, and read before this wrapper ever opens the window itself.
|
|
136
136
|
const n = l ||= !(t.m & STATUS_UNINITIALIZED) && !t.ce;
|
|
137
137
|
if (n) t.ce = true, t.l |= CONFIG_LAGS;
|
|
138
|
-
let
|
|
138
|
+
let s;
|
|
139
139
|
try {
|
|
140
|
-
|
|
140
|
+
s = e(r);
|
|
141
141
|
} catch (e) {
|
|
142
142
|
// The wrapping form: an unready source parks the node in the window,
|
|
143
143
|
// and the wait is its flight until the source's settle re-runs it.
|
|
144
|
-
if (n && e instanceof NotReadyError) ask(e);
|
|
144
|
+
if (n && e instanceof NotReadyError) ask(e); else land(o);
|
|
145
145
|
throw e;
|
|
146
146
|
}
|
|
147
|
-
if (n && typeof
|
|
148
|
-
if (isThenable(
|
|
149
|
-
ask(
|
|
150
|
-
const done = () => land(
|
|
151
|
-
|
|
152
|
-
return serve(
|
|
147
|
+
if (n && typeof s === "object" && s !== null) {
|
|
148
|
+
if (isThenable(s)) {
|
|
149
|
+
ask(s);
|
|
150
|
+
const done = () => land(s, true);
|
|
151
|
+
s.then(done, done);
|
|
152
|
+
return serve(s);
|
|
153
153
|
}
|
|
154
|
-
const e =
|
|
154
|
+
const e = s[Symbol.asyncIterator];
|
|
155
155
|
if (e) {
|
|
156
156
|
// A stream's flight ends at its first yield (or its end).
|
|
157
|
-
const r = e.call(
|
|
157
|
+
const r = e.call(s);
|
|
158
158
|
let t = true;
|
|
159
159
|
const done = () => land(o, true);
|
|
160
160
|
const o = {
|
|
@@ -162,7 +162,10 @@ GlobalQueue.er = e => lagging.size !== 0 ? lagOf(e, new Set) : undefined;
|
|
|
162
162
|
// promise, as for a plain flight: verdict and value in one flush.
|
|
163
163
|
next: e => {
|
|
164
164
|
const o = r.next(e);
|
|
165
|
-
if (t)
|
|
165
|
+
if (t) {
|
|
166
|
+
t = false;
|
|
167
|
+
if (isThenable(o)) o.then(done, done); else done();
|
|
168
|
+
}
|
|
166
169
|
return o;
|
|
167
170
|
},
|
|
168
171
|
return: e => r.return?.(e) ?? Promise.resolve({
|
|
@@ -177,7 +180,7 @@ GlobalQueue.er = e => lagging.size !== 0 ? lagOf(e, new Set) : undefined;
|
|
|
177
180
|
}
|
|
178
181
|
}
|
|
179
182
|
land(o);
|
|
180
|
-
return
|
|
183
|
+
return s;
|
|
181
184
|
}, r));
|
|
182
185
|
}
|
|
183
186
|
|