|
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