|
2 | 2 | let currentSignal: Signal | undefined;
|
3 | 3 | let commitError: Error | null = null;
|
4 | 4 |
|
5 |
| -const pending = new Set<Signal>(); |
6 |
| -/** Batch calls can be nested. 0 means that there is no batching */ |
7 |
| -let batchPending = 0; |
| 5 | +let batchPending: Set<Signal> | null = null; |
8 | 6 |
|
9 | 7 | let oldDeps = new Set<Signal>();
|
10 | 8 |
|
@@ -71,25 +69,15 @@ export class Signal<T = any> {
|
71 | 69 |
|
72 | 70 | if (this._value !== value) {
|
73 | 71 | this._value = value;
|
74 |
| - let isFirst = pending.size === 0; |
75 |
| - pending.add(this); |
76 |
| - // in batch mode this signal may be marked already |
77 |
| - if (this._pending === 0) { |
78 |
| - mark(this); |
79 |
| - } |
80 | 72 |
|
81 |
| - // this is the first change, not a computed and we are not |
82 |
| - // in batch mode: |
83 |
| - if (isFirst && batchPending === 0) { |
84 |
| - sweep(pending); |
85 |
| - pending.clear(); |
86 |
| - if (commitError) { |
87 |
| - const err = commitError; |
88 |
| - // Clear global error flag for next commit |
89 |
| - commitError = null; |
90 |
| - throw err; |
| 73 | + batch(() => { |
| 74 | + batchPending!.add(this); |
| 75 | + |
| 76 | + // in batch mode this signal may be marked already |
| 77 | + if (this._pending === 0) { |
| 78 | + mark(this); |
91 | 79 | }
|
92 |
| - } |
| 80 | + }); |
93 | 81 | }
|
94 | 82 | }
|
95 | 83 |
|
@@ -205,7 +193,10 @@ const tmpPending: Signal[] = [];
|
205 | 193 | * we don't have to care about topological sorting.
|
206 | 194 | */
|
207 | 195 | function refreshStale(signal: Signal) {
|
208 |
| - pending.delete(signal); |
| 196 | + if (batchPending) { |
| 197 | + batchPending.delete(signal); |
| 198 | + } |
| 199 | + |
209 | 200 | signal._pending = 0;
|
210 | 201 | signal._updater();
|
211 | 202 | if (commitError) {
|
@@ -270,20 +261,34 @@ export function effect(callback: () => void) {
|
270 | 261 | }
|
271 | 262 |
|
272 | 263 | export function batch<T>(cb: () => T): T {
|
273 |
| - batchPending++; |
274 |
| - try { |
| 264 | + if (batchPending !== null) { |
275 | 265 | return cb();
|
276 |
| - } finally { |
277 |
| - // Since stale signals are refreshed upwards, we need to |
278 |
| - // add pending signals in reverse |
279 |
| - let item: Signal | undefined; |
280 |
| - while ((item = tmpPending.pop()) !== undefined) { |
281 |
| - pending.add(item); |
282 |
| - } |
283 | 266 |
|
284 |
| - if (--batchPending === 0) { |
| 267 | + } else { |
| 268 | + const pending: Set<Signal> = new Set(); |
| 269 | + |
| 270 | + batchPending = pending; |
| 271 | + |
| 272 | + try { |
| 273 | + return cb(); |
| 274 | + |
| 275 | + } finally { |
| 276 | + // Since stale signals are refreshed upwards, we need to |
| 277 | + // add pending signals in reverse |
| 278 | + let item: Signal | undefined; |
| 279 | + while ((item = tmpPending.pop()) !== undefined) { |
| 280 | + pending.add(item); |
| 281 | + } |
| 282 | + |
| 283 | + batchPending = null; |
| 284 | + |
285 | 285 | sweep(pending);
|
286 |
| - pending.clear(); |
| 286 | + if (commitError) { |
| 287 | + const err = commitError; |
| 288 | + // Clear global error flag for next commit |
| 289 | + commitError = null; |
| 290 | + throw err; |
| 291 | + } |
287 | 292 | }
|
288 | 293 | }
|
289 | 294 | }
|
0 commit comments