Skip to content

Commit 76c75c3

Browse files
authored
Merge pull request #26 from tuhm1/fix-unwatch-many
Fix unwatch multiple signals
2 parents 1ec9d8e + fa6804c commit 76c75c3

File tree

2 files changed

+48
-21
lines changed

2 files changed

+48
-21
lines changed

src/wrapper.ts

+17-20
Original file line numberDiff line numberDiff line change
@@ -227,28 +227,25 @@ export namespace Signal {
227227
const node = this[NODE];
228228
assertConsumerNode(node);
229229

230-
let indicesToShift = [];
231-
for (let i = 0; i < node.producerNode.length; i++) {
230+
for (let i = node.producerNode.length - 1; i >= 0; i--) {
232231
if (signals.includes(node.producerNode[i].wrapper)) {
233232
producerRemoveLiveConsumerAtIndex(node.producerNode[i], node.producerIndexOfThis[i]);
234-
indicesToShift.push(i);
235-
}
236-
}
237-
for (const idx of indicesToShift) {
238-
// Logic copied from producerRemoveLiveConsumerAtIndex, but reversed
239-
const lastIdx = node.producerNode!.length - 1;
240-
node.producerNode![idx] = node.producerNode![lastIdx];
241-
node.producerIndexOfThis[idx] = node.producerIndexOfThis[lastIdx];
242-
243-
node.producerNode.length--;
244-
node.producerIndexOfThis.length--;
245-
node.nextProducerIndex--;
246-
247-
if (idx < node.producerNode.length) {
248-
const idxConsumer = node.producerIndexOfThis[idx];
249-
const producer = node.producerNode[idx];
250-
assertProducerNode(producer);
251-
producer.liveConsumerIndexOfThis[idxConsumer] = idx;
233+
234+
// Logic copied from producerRemoveLiveConsumerAtIndex, but reversed
235+
const lastIdx = node.producerNode!.length - 1;
236+
node.producerNode![i] = node.producerNode![lastIdx];
237+
node.producerIndexOfThis[i] = node.producerIndexOfThis[lastIdx];
238+
239+
node.producerNode.length--;
240+
node.producerIndexOfThis.length--;
241+
node.nextProducerIndex--;
242+
243+
if (i < node.producerNode.length) {
244+
const idxConsumer = node.producerIndexOfThis[i];
245+
const producer = node.producerNode[i];
246+
assertProducerNode(producer);
247+
producer.liveConsumerIndexOfThis[idxConsumer] = i;
248+
}
252249
}
253250
}
254251
}

tests/Signal/subtle/watch-unwatch.test.ts

+31-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {describe, expect, it} from 'vitest';
1+
import {describe, expect, it, vi} from 'vitest';
22
import {Signal} from '../../../src/wrapper.js';
33

44
describe('watch and unwatch', () => {
@@ -160,4 +160,34 @@ describe('watch and unwatch', () => {
160160
expect(w.getPending()).toStrictEqual([]);
161161
expect(d).toBe(4);
162162
});
163+
it('can unwatch multiple signals', async () => {
164+
const signals = [...Array(7)].map((_, i) => new Signal.State(i));
165+
const notify = vi.fn();
166+
const watcher = new Signal.subtle.Watcher(notify);
167+
const expectSources = (expected: typeof signals) => {
168+
const sources = Signal.subtle.introspectSources(watcher) as typeof signals;
169+
sources.sort((a, b) => signals.indexOf(a) - signals.indexOf(b));
170+
expected.sort((a, b) => signals.indexOf(a) - signals.indexOf(b));
171+
return expect(sources).toEqual(expected);
172+
};
173+
174+
watcher.watch(...signals);
175+
expectSources(signals);
176+
177+
const unwatched = [0, 3, 4, 6].map((i) => signals[i]);
178+
const watched = signals.filter((s) => !unwatched.includes(s));
179+
180+
watcher.unwatch(...unwatched);
181+
expectSources(watched);
182+
183+
let expectedNotifyCalls = 0;
184+
for (const signal of signals) {
185+
signal.set(signal.get() + 1);
186+
if (watched.includes(signal)) ++expectedNotifyCalls;
187+
188+
expect(notify).toHaveBeenCalledTimes(expectedNotifyCalls);
189+
190+
watcher.watch();
191+
}
192+
});
163193
});

0 commit comments

Comments
 (0)