@solidjs/signals 2.0.0-beta.19 → 2.0.0-beta.20
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.js +670 -371
- package/dist/node.cjs +1878 -1606
- package/dist/prod/affects.js +17 -21
- package/dist/prod/core/action.js +19 -6
- package/dist/prod/core/async.js +57 -71
- package/dist/prod/core/constants.js +15 -1
- package/dist/prod/core/core.js +39 -39
- package/dist/prod/core/effect.js +14 -14
- package/dist/prod/core/graph.js +1 -1
- package/dist/prod/core/heap.js +2 -2
- package/dist/prod/core/lanes.js +23 -13
- package/dist/prod/core/optimistic.js +107 -99
- package/dist/prod/core/owner.js +23 -23
- package/dist/prod/core/scheduler.js +180 -180
- package/dist/prod/core/verdict.js +12 -13
- package/dist/prod/map.js +196 -167
- package/dist/prod/signals.js +1 -1
- package/dist/prod/store/optimistic.js +103 -68
- package/dist/prod/store/reconcile.js +80 -46
- package/dist/prod/store/store.js +204 -73
- package/dist/prod/store/utils.js +61 -42
- package/dist/types/core/action.d.ts +19 -6
- package/dist/types/core/constants.d.ts +12 -0
- package/dist/types/core/dev.d.ts +7 -0
- package/dist/types/core/lanes.d.ts +2 -0
- package/dist/types/core/scheduler.d.ts +2 -6
- package/dist/types/core/types.d.ts +9 -1
- package/dist/types/store/store.d.ts +8 -2
- package/dist/types-cjs/core/action.d.cts +19 -6
- package/dist/types-cjs/core/constants.d.cts +12 -0
- package/dist/types-cjs/core/dev.d.cts +7 -0
- package/dist/types-cjs/core/lanes.d.cts +2 -0
- package/dist/types-cjs/core/scheduler.d.cts +2 -6
- package/dist/types-cjs/core/types.d.cts +9 -1
- package/dist/types-cjs/store/store.d.cts +8 -2
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EFFECT_RENDER, EFFECT_USER, STATUS_PENDING, REACTIVE_DISPOSED,
|
|
1
|
+
import { EFFECT_RENDER, EFFECT_USER, STATUS_PENDING, REACTIVE_DISPOSED, REACTIVE_ZOMBIE, NOT_PENDING, EFFECT_TRACKED, CONFIG_IN_SNAPSHOT_SCOPE, REACTIVE_SNAPSHOT_STALE, REACTIVE_OPTIMISTIC_DIRTY, REACTIVE_REASK, REACTIVE_MANUAL_WRITE, STATUS_UNINITIALIZED } from "./constants.js";
|
|
2
2
|
|
|
3
3
|
import { currentOptimisticLane } from "./core.js";
|
|
4
4
|
|
|
@@ -55,7 +55,8 @@ function registerTransientStoreNode(e) {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
function canUseSimpleSyncFlush(e) {
|
|
58
|
-
|
|
58
|
+
const t = e.N;
|
|
59
|
+
return transitions.size === 0 && activeLanes.size === 0 && e.Qt.length === 0 && t.Be.length === 0 && t._.length === 0 && t.dn.size === 0 && transientStoreNodes.size === 0;
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
function sweepTransientStoreNodes() {
|
|
@@ -70,7 +71,7 @@ function sweepTransientStoreNodes() {
|
|
|
70
71
|
// A live affects() mark keeps the node addressable: sweeping it would
|
|
71
72
|
// detach the refcount from the slot (a fresh probe would upsert a new,
|
|
72
73
|
// unmarked node for the same property).
|
|
73
|
-
if (e.
|
|
74
|
+
if (e.M) continue;
|
|
74
75
|
transientStoreNodes.delete(e);
|
|
75
76
|
e.ct?.();
|
|
76
77
|
}
|
|
@@ -89,31 +90,57 @@ function setProjectionWriteActive(e) {
|
|
|
89
90
|
projectionWriteActive = e;
|
|
90
91
|
}
|
|
91
92
|
|
|
93
|
+
/**
|
|
94
|
+
* Ambient work IS a transaction: the global queue always carries one
|
|
95
|
+
* current-transaction-shaped batch (`globalQueue._batch`). With no transition
|
|
96
|
+
* active, registrations (pending commits, optimistic nodes, affects marks,
|
|
97
|
+
* optimistic stores) land in a plain ambient batch that the plain flush
|
|
98
|
+
* finalizes; when a transition initializes it adopts the ambient batch's
|
|
99
|
+
* contents and `_batch` becomes the transition itself, so later registrations
|
|
100
|
+
* land there directly — no per-field aliasing.
|
|
101
|
+
*/ function createBatch() {
|
|
102
|
+
return {
|
|
103
|
+
Ie: clock,
|
|
104
|
+
yt: [],
|
|
105
|
+
Lt: new Map,
|
|
106
|
+
Be: [],
|
|
107
|
+
_: [],
|
|
108
|
+
dn: new Set,
|
|
109
|
+
Te: [],
|
|
110
|
+
Bt: {
|
|
111
|
+
Mt: [ [], [] ],
|
|
112
|
+
Qt: []
|
|
113
|
+
},
|
|
114
|
+
cn: false,
|
|
115
|
+
un: new Set
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
92
119
|
function mergeTransitionState(e, t) {
|
|
93
|
-
t.
|
|
120
|
+
t.cn = e;
|
|
94
121
|
e.Te.push(...t.Te);
|
|
95
122
|
for (const i of activeLanes) if (i.ve === t) i.ve = e;
|
|
96
123
|
if (t.Be.length) {
|
|
97
|
-
// Move (don't copy): the global queue may still
|
|
98
|
-
//
|
|
124
|
+
// Move (don't copy): the global queue's batch may still be the outgoing
|
|
125
|
+
// transition, and the adoption pass in initTransition would re-push its
|
|
99
126
|
// contents into the target — duplicating every entry.
|
|
100
127
|
e.Be.push(...t.Be);
|
|
101
128
|
t.Be.length = 0;
|
|
102
129
|
}
|
|
103
|
-
if (t.
|
|
104
|
-
// Move (don't copy): the global queue may still
|
|
105
|
-
//
|
|
130
|
+
if (t._.length) {
|
|
131
|
+
// Move (don't copy): the global queue's batch may still be the outgoing
|
|
132
|
+
// transition, and the adoption pass in initTransition would re-push its
|
|
106
133
|
// contents into the target — double-releasing every mark.
|
|
107
|
-
e.
|
|
108
|
-
t.
|
|
134
|
+
e._.push(...t._);
|
|
135
|
+
t._.length = 0;
|
|
109
136
|
}
|
|
110
|
-
for (const i of t.
|
|
111
|
-
for (const [i, n] of t.
|
|
112
|
-
let t = e.
|
|
113
|
-
if (!t) e.
|
|
137
|
+
for (const i of t.dn) e.dn.add(i);
|
|
138
|
+
for (const [i, n] of t.Lt) {
|
|
139
|
+
let t = e.Lt.get(i);
|
|
140
|
+
if (!t) e.Lt.set(i, t = new Set);
|
|
114
141
|
for (const e of n) t.add(e);
|
|
115
142
|
}
|
|
116
|
-
for (const i of t.
|
|
143
|
+
for (const i of t.un) e.un.add(i);
|
|
117
144
|
}
|
|
118
145
|
|
|
119
146
|
function schedule() {
|
|
@@ -123,7 +150,7 @@ function schedule() {
|
|
|
123
150
|
}
|
|
124
151
|
if (scheduled) return;
|
|
125
152
|
scheduled = true;
|
|
126
|
-
if (!syncDepth && !globalQueue.
|
|
153
|
+
if (!syncDepth && !globalQueue.Ut && !projectionWriteActive) queueMicrotask(flush);
|
|
127
154
|
}
|
|
128
155
|
|
|
129
156
|
/**
|
|
@@ -153,32 +180,32 @@ function notifyHalted() {
|
|
|
153
180
|
}
|
|
154
181
|
|
|
155
182
|
class Queue {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
183
|
+
Fe=null;
|
|
184
|
+
Mt=[ [], [] ];
|
|
185
|
+
Qt=[];
|
|
159
186
|
created=clock;
|
|
160
187
|
addChild(e) {
|
|
161
|
-
this.
|
|
162
|
-
e.
|
|
188
|
+
this.Qt.push(e);
|
|
189
|
+
e.Fe = this;
|
|
163
190
|
}
|
|
164
191
|
removeChild(e) {
|
|
165
|
-
const t = this.
|
|
192
|
+
const t = this.Qt.indexOf(e);
|
|
166
193
|
if (t >= 0) {
|
|
167
|
-
this.
|
|
168
|
-
e.
|
|
194
|
+
this.Qt.splice(t, 1);
|
|
195
|
+
e.Fe = null;
|
|
169
196
|
}
|
|
170
197
|
}
|
|
171
198
|
notify(e, t, i, n) {
|
|
172
|
-
if (this.
|
|
199
|
+
if (this.Fe) return this.Fe.notify(e, t, i, n);
|
|
173
200
|
return false;
|
|
174
201
|
}
|
|
175
202
|
run(e) {
|
|
176
|
-
if (this.
|
|
177
|
-
const t = this.
|
|
178
|
-
this.
|
|
203
|
+
if (this.Mt[e - 1].length) {
|
|
204
|
+
const t = this.Mt[e - 1];
|
|
205
|
+
this.Mt[e - 1] = [];
|
|
179
206
|
runQueue(t, e);
|
|
180
207
|
}
|
|
181
|
-
for (let t = 0; t < this.
|
|
208
|
+
for (let t = 0; t < this.Qt.length; t++) this.Qt[t].run?.(e);
|
|
182
209
|
}
|
|
183
210
|
enqueue(e, t) {
|
|
184
211
|
if (e) {
|
|
@@ -187,50 +214,48 @@ class Queue {
|
|
|
187
214
|
const i = findLane(currentOptimisticLane);
|
|
188
215
|
i.tn[e - 1].push(t);
|
|
189
216
|
} else {
|
|
190
|
-
this.
|
|
217
|
+
this.Mt[e - 1].push(t);
|
|
191
218
|
}
|
|
192
219
|
}
|
|
193
220
|
schedule();
|
|
194
221
|
}
|
|
195
222
|
stashQueues(e) {
|
|
196
|
-
e.
|
|
197
|
-
e.
|
|
198
|
-
this.
|
|
199
|
-
for (let t = 0; t < this.
|
|
200
|
-
let i = this.
|
|
201
|
-
let n = e.
|
|
223
|
+
e.Mt[0].push(...this.Mt[0]);
|
|
224
|
+
e.Mt[1].push(...this.Mt[1]);
|
|
225
|
+
this.Mt = [ [], [] ];
|
|
226
|
+
for (let t = 0; t < this.Qt.length; t++) {
|
|
227
|
+
let i = this.Qt[t];
|
|
228
|
+
let n = e.Qt[t];
|
|
202
229
|
if (!n) {
|
|
203
230
|
n = {
|
|
204
|
-
|
|
205
|
-
|
|
231
|
+
Mt: [ [], [] ],
|
|
232
|
+
Qt: []
|
|
206
233
|
};
|
|
207
|
-
e.
|
|
234
|
+
e.Qt[t] = n;
|
|
208
235
|
}
|
|
209
236
|
i.stashQueues(n);
|
|
210
237
|
}
|
|
211
238
|
}
|
|
212
239
|
restoreQueues(e) {
|
|
213
|
-
this.
|
|
214
|
-
this.
|
|
215
|
-
for (let t = 0; t < e.
|
|
216
|
-
const i = e.
|
|
217
|
-
let n = this.
|
|
240
|
+
this.Mt[0].push(...e.Mt[0]);
|
|
241
|
+
this.Mt[1].push(...e.Mt[1]);
|
|
242
|
+
for (let t = 0; t < e.Qt.length; t++) {
|
|
243
|
+
const i = e.Qt[t];
|
|
244
|
+
let n = this.Qt[t];
|
|
218
245
|
if (n) n.restoreQueues(i);
|
|
219
246
|
}
|
|
220
247
|
}
|
|
221
248
|
}
|
|
222
249
|
|
|
223
250
|
class GlobalQueue extends Queue {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
N=[];
|
|
229
|
-
Lt=new Set;
|
|
251
|
+
Ut=false;
|
|
252
|
+
// The current transaction-shaped batch: a plain ambient batch while no
|
|
253
|
+
// transition is active, the active transition itself after initTransition.
|
|
254
|
+
N=createBatch();
|
|
230
255
|
static Ce;
|
|
231
256
|
static Oe;
|
|
232
257
|
static ut;
|
|
233
|
-
static
|
|
258
|
+
static Vt=null;
|
|
234
259
|
// Store-side hook: drops a keyless affects() mark's identity scope when the
|
|
235
260
|
// carrier node's last registration releases (wired by store.ts, mirroring
|
|
236
261
|
// _clearOptimisticStore).
|
|
@@ -256,15 +281,15 @@ class GlobalQueue extends Queue {
|
|
|
256
281
|
// verdict.ts, and `pendingCheckActive`/`latestReadActive` only flip inside
|
|
257
282
|
// isPending()/latest()).
|
|
258
283
|
static _e=null;
|
|
259
|
-
static
|
|
284
|
+
static P=null;
|
|
260
285
|
static me=null;
|
|
261
286
|
static R=null;
|
|
262
287
|
static Gt=null;
|
|
263
288
|
static Pt=null;
|
|
264
|
-
static
|
|
289
|
+
static kt=null;
|
|
265
290
|
static tt=null;
|
|
266
291
|
static nt=null;
|
|
267
|
-
static
|
|
292
|
+
static wt=null;
|
|
268
293
|
// Optimistic-engine hooks (wired by core/optimistic.ts via
|
|
269
294
|
// installOptimisticEngine(), called from verdict.ts / createOptimistic /
|
|
270
295
|
// createOptimisticStore — every module that can create optimistic state).
|
|
@@ -273,22 +298,22 @@ class GlobalQueue extends Queue {
|
|
|
273
298
|
// entry, or a non-null `currentOptimisticLane`, so `!` invocations are safe
|
|
274
299
|
// once the gate holds.
|
|
275
300
|
static bt=null;
|
|
276
|
-
static
|
|
277
|
-
static
|
|
278
|
-
static
|
|
279
|
-
static
|
|
280
|
-
static
|
|
281
|
-
static gt=null;
|
|
301
|
+
static En=null;
|
|
302
|
+
static Tn=null;
|
|
303
|
+
static In=null;
|
|
304
|
+
static Nn=null;
|
|
305
|
+
static On=null;
|
|
282
306
|
static Dt=null;
|
|
307
|
+
static gt=null;
|
|
283
308
|
static ht=null;
|
|
284
|
-
static
|
|
309
|
+
static vt=null;
|
|
285
310
|
static $e=null;
|
|
286
311
|
static et=null;
|
|
287
312
|
static Xe=null;
|
|
288
|
-
static
|
|
313
|
+
static mn=null;
|
|
289
314
|
flush() {
|
|
290
|
-
if (this.
|
|
291
|
-
this.
|
|
315
|
+
if (this.Ut) return;
|
|
316
|
+
this.Ut = true;
|
|
292
317
|
try {
|
|
293
318
|
if (false) ;
|
|
294
319
|
runHeap(dirtyQueue, GlobalQueue.Ce);
|
|
@@ -297,38 +322,48 @@ class GlobalQueue extends Queue {
|
|
|
297
322
|
if (!e) {
|
|
298
323
|
const e = activeTransition;
|
|
299
324
|
runHeap(zombieQueue, GlobalQueue.Ce);
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
this.N = [];
|
|
304
|
-
this.Lt = new Set;
|
|
325
|
+
// Detach: the stashed transition keeps its batch; ambient work that
|
|
326
|
+
// follows lands in a fresh one.
|
|
327
|
+
currentBatch = this.N = createBatch();
|
|
305
328
|
// Run lane effects immediately (before stashing) - lanes with no pending async
|
|
306
329
|
if (activeLanes.size) {
|
|
307
|
-
GlobalQueue.
|
|
308
|
-
GlobalQueue.
|
|
330
|
+
GlobalQueue.On(EFFECT_RENDER);
|
|
331
|
+
GlobalQueue.On(EFFECT_USER);
|
|
309
332
|
}
|
|
310
|
-
this.stashQueues(e.
|
|
333
|
+
this.stashQueues(e.Bt);
|
|
311
334
|
clock++;
|
|
312
335
|
scheduled = dirtyQueue.EE >= dirtyQueue.Le;
|
|
313
|
-
reassignPendingTransition(e.
|
|
336
|
+
reassignPendingTransition(e.yt);
|
|
314
337
|
activeTransition = null;
|
|
315
338
|
// The stash pass (committed-view rerun of plain optimistic signals)
|
|
316
339
|
// wraps finalizePureQueue in the engine; a non-empty _optimisticNodes
|
|
317
340
|
// means _optimisticWrite ran, which installed the hook.
|
|
318
|
-
if (!e.Te.length && !e.
|
|
319
|
-
GlobalQueue.
|
|
341
|
+
if (!e.Te.length && !e.Lt.size && e.Be.length) {
|
|
342
|
+
GlobalQueue.Tn(e);
|
|
320
343
|
} else {
|
|
321
344
|
finalizePureQueue(null, true);
|
|
322
345
|
}
|
|
323
346
|
return;
|
|
324
347
|
}
|
|
325
|
-
this.Yt !== activeTransition.Yt && this.Yt.push(...activeTransition.Yt);
|
|
326
|
-
this.restoreQueues(activeTransition.Jt);
|
|
327
|
-
transitions.delete(activeTransition);
|
|
328
348
|
const t = activeTransition;
|
|
349
|
+
const i = this.N;
|
|
350
|
+
i !== t && i.yt.push(...t.yt);
|
|
351
|
+
this.restoreQueues(t.Bt);
|
|
352
|
+
transitions.delete(t);
|
|
329
353
|
activeTransition = null;
|
|
330
|
-
reassignPendingTransition(
|
|
354
|
+
reassignPendingTransition(i.yt);
|
|
331
355
|
finalizePureQueue(t);
|
|
356
|
+
if (i === t) {
|
|
357
|
+
// Drop the dead Transition wrapper but keep its (drained) containers
|
|
358
|
+
// as the ambient batch — late registrations during finalization live
|
|
359
|
+
// there and must survive to the next flush.
|
|
360
|
+
const e = createBatch();
|
|
361
|
+
e.yt = i.yt;
|
|
362
|
+
e.Be = i.Be;
|
|
363
|
+
e._ = i._;
|
|
364
|
+
e.dn = i.dn;
|
|
365
|
+
currentBatch = this.N = e;
|
|
366
|
+
}
|
|
332
367
|
} else {
|
|
333
368
|
if (canUseSimpleSyncFlush(this)) {
|
|
334
369
|
commitPendingNodes();
|
|
@@ -345,15 +380,15 @@ class GlobalQueue extends Queue {
|
|
|
345
380
|
// Check if finalization added items to the heap (from optimistic reversion)
|
|
346
381
|
scheduled = dirtyQueue.EE >= dirtyQueue.Le;
|
|
347
382
|
// Run lane effects first (for ready lanes), then regular effects
|
|
348
|
-
activeLanes.size && GlobalQueue.
|
|
383
|
+
activeLanes.size && GlobalQueue.On(EFFECT_RENDER);
|
|
349
384
|
this.run(EFFECT_RENDER);
|
|
350
|
-
activeLanes.size && GlobalQueue.
|
|
385
|
+
activeLanes.size && GlobalQueue.On(EFFECT_USER);
|
|
351
386
|
this.run(EFFECT_USER);
|
|
352
387
|
if (false) ;
|
|
353
388
|
if (false && !scheduled && !activeTransition && transitions.size === 0 && activeLanes.size === 0) ;
|
|
354
389
|
if (false) ;
|
|
355
390
|
} finally {
|
|
356
|
-
this.
|
|
391
|
+
this.Ut = false;
|
|
357
392
|
}
|
|
358
393
|
}
|
|
359
394
|
notify(e, t, i, n) {
|
|
@@ -363,8 +398,8 @@ class GlobalQueue extends Queue {
|
|
|
363
398
|
const t = n !== undefined ? n : e.k;
|
|
364
399
|
if (activeTransition && t) {
|
|
365
400
|
const i = t.source;
|
|
366
|
-
let n = activeTransition.
|
|
367
|
-
if (!n) activeTransition.
|
|
401
|
+
let n = activeTransition.Lt.get(i);
|
|
402
|
+
if (!n) activeTransition.Lt.set(i, n = new Set);
|
|
368
403
|
const s = n.size;
|
|
369
404
|
n.add(e);
|
|
370
405
|
if (n.size !== s) schedule();
|
|
@@ -379,21 +414,7 @@ class GlobalQueue extends Queue {
|
|
|
379
414
|
if (e && e === activeTransition) return;
|
|
380
415
|
if (!e && activeTransition && activeTransition.Ie === clock) return;
|
|
381
416
|
if (!activeTransition) {
|
|
382
|
-
activeTransition = e ??
|
|
383
|
-
Ie: clock,
|
|
384
|
-
Yt: [],
|
|
385
|
-
qt: new Map,
|
|
386
|
-
Be: [],
|
|
387
|
-
N: [],
|
|
388
|
-
Lt: new Set,
|
|
389
|
-
Te: [],
|
|
390
|
-
Jt: {
|
|
391
|
-
zt: [ [], [] ],
|
|
392
|
-
wt: []
|
|
393
|
-
},
|
|
394
|
-
Ht: false,
|
|
395
|
-
Qt: new Set
|
|
396
|
-
};
|
|
417
|
+
activeTransition = e ?? createBatch();
|
|
397
418
|
} else if (e) {
|
|
398
419
|
const t = activeTransition;
|
|
399
420
|
mergeTransitionState(e, t);
|
|
@@ -402,61 +423,37 @@ class GlobalQueue extends Queue {
|
|
|
402
423
|
}
|
|
403
424
|
transitions.add(activeTransition);
|
|
404
425
|
activeTransition.Ie = clock;
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
426
|
+
const t = this.N;
|
|
427
|
+
if (t !== activeTransition) {
|
|
428
|
+
// Adopt the ambient batch into the transaction, then make the
|
|
429
|
+
// transaction the batch so later registrations land there directly.
|
|
430
|
+
// Pending and optimistic nodes are re-stamped as the transaction's;
|
|
431
|
+
// marks don't hijack the node's _transition — a mark on a plain signal
|
|
432
|
+
// must not entangle unrelated writes to it; the same rule holds one hop
|
|
433
|
+
// downstream: propagation never queues pended subscribers as pending
|
|
434
|
+
// nodes, see propagateAffectsMark, #2893.
|
|
435
|
+
for (let e = 0; e < t.yt.length; e++) {
|
|
436
|
+
const i = t.yt[e];
|
|
437
|
+
i.ve = activeTransition;
|
|
438
|
+
activeTransition.yt.push(i);
|
|
415
439
|
}
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
const t = this.Be[e];
|
|
421
|
-
t.ve = activeTransition;
|
|
422
|
-
activeTransition.Be.push(t);
|
|
440
|
+
for (let e = 0; e < t.Be.length; e++) {
|
|
441
|
+
const i = t.Be[e];
|
|
442
|
+
i.ve = activeTransition;
|
|
443
|
+
activeTransition.Be.push(i);
|
|
423
444
|
}
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
// Adopt ambient marks into the transaction (marks don't hijack the
|
|
428
|
-
// node's _transition — a mark on a plain signal must not entangle
|
|
429
|
-
// unrelated writes to it; the same rule holds one hop downstream:
|
|
430
|
-
// propagation never queues pended subscribers as pending nodes, see
|
|
431
|
-
// propagateAffectsMark, #2893). After adoption the queue aliases the
|
|
432
|
-
// transition's array, so later registrations land there directly.
|
|
433
|
-
activeTransition.N.push(...this.N);
|
|
434
|
-
this.N = activeTransition.N;
|
|
445
|
+
if (t._.length) activeTransition._.push(...t._);
|
|
446
|
+
for (const e of t.dn) activeTransition.dn.add(e);
|
|
447
|
+
currentBatch = this.N = activeTransition;
|
|
435
448
|
}
|
|
436
449
|
for (const e of activeLanes) {
|
|
437
450
|
if (!e.ve) e.ve = activeTransition;
|
|
438
451
|
}
|
|
439
|
-
if (this.Lt !== activeTransition.Lt) {
|
|
440
|
-
for (const e of this.Lt) activeTransition.Lt.add(e);
|
|
441
|
-
this.Lt = activeTransition.Lt;
|
|
442
|
-
}
|
|
443
452
|
}
|
|
444
453
|
}
|
|
445
454
|
|
|
446
455
|
function queuePendingNode(e) {
|
|
447
|
-
|
|
448
|
-
globalQueue.Yt.push(e);
|
|
449
|
-
return;
|
|
450
|
-
}
|
|
451
|
-
if (globalQueue.xt === null && globalQueue.Yt.length === 0) {
|
|
452
|
-
globalQueue.xt = e;
|
|
453
|
-
return;
|
|
454
|
-
}
|
|
455
|
-
if (globalQueue.xt !== null) {
|
|
456
|
-
globalQueue.Yt.push(globalQueue.xt);
|
|
457
|
-
globalQueue.xt = null;
|
|
458
|
-
}
|
|
459
|
-
globalQueue.Yt.push(e);
|
|
456
|
+
currentBatch.yt.push(e);
|
|
460
457
|
}
|
|
461
458
|
|
|
462
459
|
// Sticky: flips true on the first refresh() ever (the only setter of
|
|
@@ -474,23 +471,23 @@ function insertSubs(e, t = false) {
|
|
|
474
471
|
const i = e.Je || currentOptimisticLane;
|
|
475
472
|
const n = e.Ye !== undefined;
|
|
476
473
|
const s = reaskArmed;
|
|
477
|
-
for (let
|
|
474
|
+
for (let r = e.p; r !== null; r = r.de) {
|
|
478
475
|
// A value-change notification is a new question for the subscriber: any
|
|
479
476
|
// pending re-ask mark (refresh) it carried is superseded.
|
|
480
|
-
if (s)
|
|
481
|
-
if (n &&
|
|
482
|
-
|
|
477
|
+
if (s) r.Ee.u &= ~REACTIVE_REASK;
|
|
478
|
+
if (n && r.Ee.U & CONFIG_IN_SNAPSHOT_SCOPE) {
|
|
479
|
+
r.Ee.u |= REACTIVE_SNAPSHOT_STALE;
|
|
483
480
|
continue;
|
|
484
481
|
}
|
|
485
482
|
if (t && i) {
|
|
486
|
-
|
|
487
|
-
assignOrMergeLane(
|
|
483
|
+
r.Ee.u |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
484
|
+
assignOrMergeLane(r.Ee, i);
|
|
488
485
|
} else if (t) {
|
|
489
|
-
|
|
486
|
+
r.Ee.u |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
490
487
|
// No source lane means reversion - clear subscriber's lane so effects go to regular queue
|
|
491
|
-
|
|
488
|
+
r.Ee.Je = undefined;
|
|
492
489
|
}
|
|
493
|
-
enqueueSub(
|
|
490
|
+
enqueueSub(r.Ee);
|
|
494
491
|
}
|
|
495
492
|
}
|
|
496
493
|
|
|
@@ -517,11 +514,7 @@ function commitPendingNode(e) {
|
|
|
517
514
|
}
|
|
518
515
|
|
|
519
516
|
function commitPendingNodes() {
|
|
520
|
-
|
|
521
|
-
commitPendingNode(globalQueue.xt);
|
|
522
|
-
globalQueue.xt = null;
|
|
523
|
-
}
|
|
524
|
-
const e = globalQueue.Yt;
|
|
517
|
+
const e = currentBatch.yt;
|
|
525
518
|
for (let t = 0; t < e.length; t++) {
|
|
526
519
|
commitPendingNode(e[t]);
|
|
527
520
|
}
|
|
@@ -533,42 +526,42 @@ function finalizePureQueue(e = null, t = false) {
|
|
|
533
526
|
// For completing transitions or no-transition, resolve pending and revert optimistic
|
|
534
527
|
const i = !t;
|
|
535
528
|
if (i) commitPendingNodes();
|
|
536
|
-
if (!t && globalQueue.
|
|
529
|
+
if (!t && globalQueue.Qt.length) checkBoundaryChildren(globalQueue);
|
|
537
530
|
const n = dirtyQueue.EE >= dirtyQueue.Le;
|
|
538
531
|
if (n) runHeap(dirtyQueue, GlobalQueue.Ce);
|
|
539
532
|
if (i) {
|
|
540
533
|
if (n) commitPendingNodes();
|
|
534
|
+
// The settling batch: the completing transaction's, or the ambient one.
|
|
535
|
+
const t = e ?? globalQueue.N;
|
|
541
536
|
// Optimistic reversion: a non-empty batch means _optimisticWrite ran,
|
|
542
537
|
// which installed the engine's hooks.
|
|
543
|
-
|
|
544
|
-
if (t.length) GlobalQueue.Ut(t);
|
|
538
|
+
if (t.Be.length) GlobalQueue.En(t.Be);
|
|
545
539
|
// Replay entanglement: subs recorded by the read-time gate get rescheduled
|
|
546
540
|
// so they re-run with the now-committed values visible.
|
|
547
|
-
if (e && e.
|
|
548
|
-
for (const t of e.
|
|
541
|
+
if (e && e.un.size) {
|
|
542
|
+
for (const t of e.un) {
|
|
549
543
|
if (t.u & REACTIVE_DISPOSED) continue;
|
|
550
544
|
enqueueSub(t);
|
|
551
545
|
}
|
|
552
|
-
e.
|
|
546
|
+
e.un.clear();
|
|
553
547
|
}
|
|
554
548
|
// Declared motion ends with the transaction: settle (or plain flush end
|
|
555
549
|
// for ambient marks) releases each registration's refcount. A non-empty
|
|
556
550
|
// batch means registerAffectsMark ran, which installed the hook.
|
|
557
|
-
|
|
558
|
-
if (i.length) GlobalQueue.h(i);
|
|
559
|
-
const s = e ? e.Lt : globalQueue.Lt;
|
|
551
|
+
if (t._.length) GlobalQueue.h(t._);
|
|
560
552
|
// A non-empty set means trackOptimisticStore ran, which installed the
|
|
561
553
|
// hook; the hook iterates, clears, and schedules (keeping the loop out of
|
|
562
|
-
// core lets esbuild shake it — rollup already folds the null guard).
|
|
563
|
-
|
|
554
|
+
// core lets esbuild shake it — rollup already folds the null guard). The
|
|
555
|
+
// completing transition scopes the clear to its own layer keys (#2899).
|
|
556
|
+
if (t.dn.size) GlobalQueue.Vt(t.dn, e);
|
|
564
557
|
sweepTransientStoreNodes();
|
|
565
558
|
// Lanes only enter activeLanes through the engine's getOrCreateLane.
|
|
566
|
-
if (activeLanes.size) GlobalQueue.
|
|
559
|
+
if (activeLanes.size) GlobalQueue.Nn(e);
|
|
567
560
|
}
|
|
568
561
|
}
|
|
569
562
|
|
|
570
563
|
function checkBoundaryChildren(e) {
|
|
571
|
-
for (const t of e.
|
|
564
|
+
for (const t of e.Qt) {
|
|
572
565
|
t.Se?.();
|
|
573
566
|
checkBoundaryChildren(t);
|
|
574
567
|
}
|
|
@@ -598,6 +591,13 @@ function reassignPendingTransition(e) {
|
|
|
598
591
|
|
|
599
592
|
const globalQueue = new GlobalQueue;
|
|
600
593
|
|
|
594
|
+
// Hot-path mirror of `globalQueue._batch`: `queuePendingNode` runs once per
|
|
595
|
+
// staged write and `commitPendingNodes` once per flush, and the extra
|
|
596
|
+
// property hop through `_batch` was a measured instruction-count regression
|
|
597
|
+
// (CodSpeed update1to1, PR #2905). The field stays authoritative for
|
|
598
|
+
// cross-module readers; every `_batch` assignment updates both.
|
|
599
|
+
let currentBatch = globalQueue.N;
|
|
600
|
+
|
|
601
601
|
function flush(e) {
|
|
602
602
|
if (e) {
|
|
603
603
|
syncDepth++;
|
|
@@ -613,7 +613,7 @@ function flush(e) {
|
|
|
613
613
|
}
|
|
614
614
|
}
|
|
615
615
|
}
|
|
616
|
-
if (globalQueue.
|
|
616
|
+
if (globalQueue.Ut) {
|
|
617
617
|
return;
|
|
618
618
|
}
|
|
619
619
|
if (halted) return;
|
|
@@ -630,7 +630,7 @@ function runQueue(e, t) {
|
|
|
630
630
|
|
|
631
631
|
function reporterBlocksSource(e, t) {
|
|
632
632
|
if (e.u & (REACTIVE_ZOMBIE | REACTIVE_DISPOSED)) return false;
|
|
633
|
-
if (e.m
|
|
633
|
+
if (e.m?.has(t)) return true;
|
|
634
634
|
for (let i = e.S; i; i = i.st) {
|
|
635
635
|
let e = i.ot;
|
|
636
636
|
while (e) {
|
|
@@ -642,10 +642,10 @@ function reporterBlocksSource(e, t) {
|
|
|
642
642
|
}
|
|
643
643
|
|
|
644
644
|
function transitionComplete(e) {
|
|
645
|
-
if (e.
|
|
645
|
+
if (e.cn) return true;
|
|
646
646
|
if (e.Te.length) return false;
|
|
647
647
|
let t = true;
|
|
648
|
-
for (const [i, n] of e.
|
|
648
|
+
for (const [i, n] of e.Lt) {
|
|
649
649
|
let s = false;
|
|
650
650
|
for (const e of n) {
|
|
651
651
|
if (reporterBlocksSource(e, i)) {
|
|
@@ -654,7 +654,7 @@ function transitionComplete(e) {
|
|
|
654
654
|
}
|
|
655
655
|
n.delete(e);
|
|
656
656
|
}
|
|
657
|
-
if (!s) e.
|
|
657
|
+
if (!s) e.Lt.delete(i); else if (i.i & STATUS_PENDING && i.k?.source === i) {
|
|
658
658
|
t = false;
|
|
659
659
|
break;
|
|
660
660
|
}
|
|
@@ -662,13 +662,13 @@ function transitionComplete(e) {
|
|
|
662
662
|
// Override blockage lives with the engine. Absent hook = "no optimistic
|
|
663
663
|
// blockage", which is exact: only _optimisticWrite (engine) pushes to
|
|
664
664
|
// _optimisticNodes, so without the engine the loop was vacuous anyway.
|
|
665
|
-
if (t && e.Be.length && GlobalQueue.
|
|
666
|
-
t && (e.
|
|
665
|
+
if (t && e.Be.length && GlobalQueue.In(e)) t = false;
|
|
666
|
+
t && (e.cn = true);
|
|
667
667
|
return t;
|
|
668
668
|
}
|
|
669
669
|
|
|
670
670
|
function currentTransition(e) {
|
|
671
|
-
while (e.
|
|
671
|
+
while (e.cn && typeof e.cn === "object") e = e.cn;
|
|
672
672
|
return e;
|
|
673
673
|
}
|
|
674
674
|
|