@solidjs/signals 0.9.0 → 0.9.2

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 CHANGED
@@ -132,6 +132,7 @@ function adjustHeight(el, heap) {
132
132
  }
133
133
  }
134
134
  const transitions = new Set();
135
+ let optimisticRun = false;
135
136
  const dirtyQueue = { _heap: new Array(2e3).fill(undefined), _marked: false, _min: 0, _max: 0 };
136
137
  const zombieQueue = { _heap: new Array(2e3).fill(undefined), _marked: false, _min: 0, _max: 0 };
137
138
  let clock = 0;
@@ -203,6 +204,7 @@ class Queue {
203
204
  class GlobalQueue extends Queue {
204
205
  _running = false;
205
206
  _pendingNodes = [];
207
+ _optimisticNodes = [];
206
208
  static _update;
207
209
  static _dispose;
208
210
  flush() {
@@ -212,31 +214,24 @@ class GlobalQueue extends Queue {
212
214
  runHeap(dirtyQueue, GlobalQueue._update);
213
215
  if (activeTransition) {
214
216
  if (!transitionComplete(activeTransition)) {
217
+ let t = activeTransition;
215
218
  runHeap(zombieQueue, GlobalQueue._update);
216
219
  this._pendingNodes = [];
217
220
  this.stashQueues(activeTransition.queueStash);
218
221
  clock++;
219
222
  scheduled = false;
220
- runPending(activeTransition.pendingNodes, true);
223
+ runTransitionPending(activeTransition.pendingNodes, true);
221
224
  activeTransition = null;
225
+ runOptimistic(t);
222
226
  return;
223
227
  }
224
228
  this._pendingNodes.push(...activeTransition.pendingNodes);
225
229
  this.restoreQueues(activeTransition.queueStash);
226
230
  transitions.delete(activeTransition);
227
231
  activeTransition = null;
228
- if (runPending(this._pendingNodes, false)) runHeap(dirtyQueue, GlobalQueue._update);
232
+ runTransitionPending(this._pendingNodes, false);
229
233
  } else if (transitions.size) runHeap(zombieQueue, GlobalQueue._update);
230
- for (let i = 0; i < this._pendingNodes.length; i++) {
231
- const n = this._pendingNodes[i];
232
- if (n._pendingValue !== NOT_PENDING) {
233
- n._value = n._pendingValue;
234
- n._pendingValue = NOT_PENDING;
235
- if (n._type) n._modified = true;
236
- }
237
- if (n._fn) GlobalQueue._dispose(n, false, true);
238
- }
239
- this._pendingNodes.length = 0;
234
+ runOptimistic();
240
235
  clock++;
241
236
  scheduled = false;
242
237
  this.run(EFFECT_RENDER);
@@ -264,7 +259,9 @@ class GlobalQueue extends Queue {
264
259
  time: clock,
265
260
  pendingNodes: [],
266
261
  asyncNodes: [],
267
- queueStash: { _queues: [[], []], _children: [] }
262
+ optimisticNodes: [],
263
+ queueStash: { _queues: [[], []], _children: [] },
264
+ done: false
268
265
  };
269
266
  }
270
267
  transitions.add(activeTransition);
@@ -274,26 +271,66 @@ class GlobalQueue extends Queue {
274
271
  n._transition = activeTransition;
275
272
  activeTransition.pendingNodes.push(n);
276
273
  }
274
+ for (let i = 0; i < this._optimisticNodes.length; i++) {
275
+ const n = this._optimisticNodes[i];
276
+ n._transition = activeTransition;
277
+ activeTransition.optimisticNodes.push(n);
278
+ }
277
279
  this._pendingNodes = activeTransition.pendingNodes;
280
+ this._optimisticNodes = activeTransition.optimisticNodes;
281
+ }
282
+ }
283
+ function notifySubs(node) {
284
+ for (let s = node._subs; s !== null; s = s._nextSub) {
285
+ const queue = s._sub._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue;
286
+ if (queue._min > s._sub._height) queue._min = s._sub._height;
287
+ insertIntoHeap(s._sub, queue);
278
288
  }
279
289
  }
280
- function runPending(pendingNodes, value) {
281
- let needsReset = false;
290
+ function runOptimistic(activeTransition = null) {
291
+ let resolvePending = !activeTransition;
292
+ const optimisticNodes = globalQueue._optimisticNodes;
293
+ optimisticRun = true;
294
+ for (let i = 0; i < optimisticNodes.length; i++) {
295
+ const n = optimisticNodes[i];
296
+ if (
297
+ !activeTransition &&
298
+ (!n._transition || n._transition.done) &&
299
+ n._pendingValue !== NOT_PENDING
300
+ ) {
301
+ n._value = n._pendingValue;
302
+ n._pendingValue = NOT_PENDING;
303
+ }
304
+ n._transition = activeTransition;
305
+ notifySubs(n);
306
+ }
307
+ globalQueue._optimisticNodes = [];
308
+ if (dirtyQueue._max >= dirtyQueue._min) {
309
+ resolvePending = true;
310
+ runHeap(dirtyQueue, GlobalQueue._update);
311
+ }
312
+ optimisticRun = false;
313
+ resolvePending && runPending(globalQueue._pendingNodes);
314
+ }
315
+ function runPending(pendingNodes) {
316
+ for (let i = 0; i < pendingNodes.length; i++) {
317
+ const n = pendingNodes[i];
318
+ if (n._pendingValue !== NOT_PENDING) {
319
+ n._value = n._pendingValue;
320
+ n._pendingValue = NOT_PENDING;
321
+ if (n._type) n._modified = true;
322
+ }
323
+ if (n._fn) GlobalQueue._dispose(n, false, true);
324
+ }
325
+ pendingNodes.length = 0;
326
+ }
327
+ function runTransitionPending(pendingNodes, value) {
282
328
  const p = pendingNodes.slice();
283
329
  for (let i = 0; i < p.length; i++) {
284
330
  const n = p[i];
285
331
  n._transition = activeTransition;
286
- if (n._pendingCheck) {
287
- n._pendingCheck._set(value);
288
- needsReset = true;
289
- }
290
- if (n._pendingSignal && n._pendingSignal._pendingValue !== NOT_PENDING) {
291
- n._pendingSignal._set(n._pendingSignal._pendingValue);
292
- n._pendingSignal._pendingValue = NOT_PENDING;
293
- needsReset = true;
294
- }
332
+ if (n._pendingCheck) n._pendingCheck._set(value);
295
333
  }
296
- return needsReset;
297
334
  }
298
335
  const globalQueue = new GlobalQueue();
299
336
  function flush() {
@@ -307,6 +344,7 @@ function runQueue(queue, type) {
307
344
  for (let i = 0; i < queue.length; i++) queue[i](type);
308
345
  }
309
346
  function transitionComplete(transition) {
347
+ if (transition.done) return true;
310
348
  let done = true;
311
349
  for (let i = 0; i < transition.asyncNodes.length; i++) {
312
350
  if (transition.asyncNodes[i]._statusFlags & STATUS_PENDING) {
@@ -314,6 +352,7 @@ function transitionComplete(transition) {
314
352
  break;
315
353
  }
316
354
  }
355
+ done && (transition.done = true);
317
356
  return done;
318
357
  }
319
358
  function runInTransition(el, recompute) {
@@ -330,13 +369,6 @@ let pendingValueCheck = false;
330
369
  let pendingCheck = null;
331
370
  let refreshing = false;
332
371
  let context = null;
333
- function notifySubs(node) {
334
- for (let s = node._subs; s !== null; s = s._nextSub) {
335
- const queue = s._sub._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue;
336
- if (queue._min > s._sub._height) queue._min = s._sub._height;
337
- insertIntoHeap(s._sub, queue);
338
- }
339
- }
340
372
  function recompute(el, create = false) {
341
373
  const honoraryOptimistic = el._type && el._transition != activeTransition;
342
374
  if (!create) {
@@ -357,7 +389,10 @@ function recompute(el, create = false) {
357
389
  el._depsTail = null;
358
390
  el._flags = REACTIVE_RECOMPUTING_DEPS;
359
391
  el._time = clock;
360
- let value = el._pendingValue === NOT_PENDING ? el._value : el._pendingValue;
392
+ let value =
393
+ el._pendingValue === NOT_PENDING || (el._optimistic && el._transition)
394
+ ? el._value
395
+ : el._pendingValue;
361
396
  let oldHeight = el._height;
362
397
  let prevStatusFlags = el._statusFlags;
363
398
  let prevError = el._error;
@@ -402,21 +437,19 @@ function recompute(el, create = false) {
402
437
  if (valueChanged) {
403
438
  if (create || el._optimistic || honoraryOptimistic) el._value = value;
404
439
  else el._pendingValue = value;
405
- if (el._pendingSignal) el._pendingSignal._pendingValue = value;
406
- }
407
- for (let s = el._subs; s !== null; s = s._nextSub) {
408
- const queue = s._sub._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue;
409
- if (s._sub._height < el._height && queue._min > s._sub._height) queue._min = s._sub._height;
410
- insertIntoHeap(s._sub, queue);
440
+ if (el._pendingSignal) setSignal(el._pendingSignal, value);
411
441
  }
442
+ (!el._optimistic || optimisticRun) && notifySubs(el);
412
443
  } else if (el._height != oldHeight) {
413
444
  for (let s = el._subs; s !== null; s = s._nextSub) {
414
445
  insertIntoHeapHeight(s._sub, s._sub._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue);
415
446
  }
416
447
  }
417
- if ((!create || el._statusFlags & STATUS_PENDING) && !el._optimistic && !el._transition)
448
+ el._optimistic && !optimisticRun && globalQueue._optimisticNodes.push(el);
449
+ (!create || el._statusFlags & STATUS_PENDING) &&
450
+ !el._transition &&
418
451
  globalQueue._pendingNodes.push(el);
419
- if (el._transition && honoraryOptimistic) runInTransition(el, recompute);
452
+ el._transition && honoraryOptimistic && runInTransition(el, recompute);
420
453
  }
421
454
  function handleAsync(el, result, setter) {
422
455
  const isObject = typeof result === "object" && result !== null;
@@ -667,7 +700,7 @@ function computed(fn, initialValue, options) {
667
700
  }
668
701
  }
669
702
  if (parent) self._height = parent._height + 1;
670
- recompute(self, true);
703
+ !options?.lazy && recompute(self, true);
671
704
  return self;
672
705
  }
673
706
  function signal(v, options, firewall = null) {
@@ -737,7 +770,6 @@ function read(el) {
737
770
  if (!el._pendingSignal) {
738
771
  el._pendingSignal = signal(el._value);
739
772
  el._pendingSignal._optimistic = true;
740
- el._pendingSignal._set = v => setSignal(el._pendingSignal, v);
741
773
  }
742
774
  pendingValueCheck = false;
743
775
  try {
@@ -763,7 +795,9 @@ function read(el) {
763
795
  return !c ||
764
796
  el._optimistic ||
765
797
  el._pendingValue === NOT_PENDING ||
766
- (stale && !pendingCheck && el._transition && activeTransition !== el._transition)
798
+ (stale &&
799
+ !pendingCheck &&
800
+ (c._optimistic || (el._transition && activeTransition !== el._transition)))
767
801
  ? el._value
768
802
  : el._pendingValue;
769
803
  }
@@ -771,7 +805,11 @@ function setSignal(el, v) {
771
805
  if (!el._pureWrite && context && el._firewall !== context)
772
806
  console.warn("A Signal was written to in an owned scope.");
773
807
  if (typeof v === "function") {
774
- v = v(el._pendingValue === NOT_PENDING ? el._value : el._pendingValue);
808
+ v = v(
809
+ el._pendingValue === NOT_PENDING || (el._optimistic && el._transition)
810
+ ? el._value
811
+ : el._pendingValue
812
+ );
775
813
  }
776
814
  const valueChanged =
777
815
  !el._equals ||
@@ -786,11 +824,11 @@ function setSignal(el, v) {
786
824
  if (el._pendingValue === NOT_PENDING) globalQueue._pendingNodes.push(el);
787
825
  el._pendingValue = v;
788
826
  }
789
- if (el._pendingSignal) el._pendingSignal._pendingValue = v;
827
+ if (el._pendingSignal) setSignal(el._pendingSignal, v);
790
828
  }
791
829
  setStatusFlags(el, STATUS_NONE);
792
830
  el._time = clock;
793
- notifySubs(el);
831
+ el._optimistic && !optimisticRun ? globalQueue._optimisticNodes.push(el) : notifySubs(el);
794
832
  schedule();
795
833
  return v;
796
834
  }
@@ -1060,7 +1098,30 @@ function resolve(fn) {
1060
1098
  });
1061
1099
  }
1062
1100
  function createOptimistic(first, second, third) {
1063
- return {};
1101
+ if (typeof first === "function") {
1102
+ const node = computed(
1103
+ prev => {
1104
+ let n = node || getOwner();
1105
+ n._pendingValue = first(prev);
1106
+ return prev;
1107
+ },
1108
+ second,
1109
+ third
1110
+ );
1111
+ node._optimistic = true;
1112
+ return [read.bind(null, node), setSignal.bind(null, node)];
1113
+ }
1114
+ const o = getOwner();
1115
+ const needsId = o?.id != null;
1116
+ const node = signal(first, needsId ? { id: getNextChildId(o), ...second } : second);
1117
+ node._optimistic = true;
1118
+ return [
1119
+ read.bind(null, node),
1120
+ v => {
1121
+ node._pendingValue = first;
1122
+ return setSignal(node, v);
1123
+ }
1124
+ ];
1064
1125
  }
1065
1126
  function onSettled(callback) {
1066
1127
  let cleanup;