Skip to content

Commit 8cbf2c2

Browse files
committed
add flush to remote connection
1 parent ae3e737 commit 8cbf2c2

File tree

3 files changed

+107
-7
lines changed

3 files changed

+107
-7
lines changed

.changeset/sour-timers-fail.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@remote-dom/core': minor
3+
---
4+
5+
add flush method to BatchingRemoteConnection

packages/core/source/elements/connection.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,28 @@ export class BatchingRemoteConnection {
2525
}
2626

2727
mutate(records: any[]) {
28-
let queued = this.#queued;
28+
const queued = this.#queued;
29+
30+
this.#queued ??= [];
31+
this.#queued.push(...records);
2932

3033
if (queued) {
31-
queued.push(...records);
3234
return;
3335
}
3436

35-
queued = [...records];
36-
this.#queued = queued;
37-
3837
this.#batch(() => {
39-
this.#connection.mutate(queued);
40-
this.#queued = undefined;
38+
this.flush();
4139
});
4240
}
41+
42+
flush() {
43+
if (!this.#queued) {
44+
return;
45+
}
46+
47+
this.#connection.mutate(this.#queued);
48+
this.#queued = undefined;
49+
}
4350
}
4451

4552
function createDefaultBatchFunction() {
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import '../../polyfill.ts';
2+
3+
import {describe, expect, it, vi, type MockedObject} from 'vitest';
4+
5+
import {BatchingRemoteConnection, RemoteConnection} from '../../elements';
6+
7+
describe('BatchingRemoteConnection', () => {
8+
it('batches mutations', async () => {
9+
const connection = createRemoteConnectionSpy();
10+
const batchingConnection = new BatchingRemoteConnection(connection);
11+
12+
batchingConnection.mutate([1, 2, 3]);
13+
batchingConnection.mutate([4, 5, 6]);
14+
15+
expect(connection.mutate).not.toHaveBeenCalled();
16+
17+
await waitForNextTask();
18+
19+
expect(connection.mutate).toHaveBeenCalledTimes(1);
20+
expect(connection.mutate).toHaveBeenCalledWith([1, 2, 3, 4, 5, 6]);
21+
22+
batchingConnection.mutate([7, 8, 9]);
23+
24+
expect(connection.mutate).toHaveBeenCalledTimes(1);
25+
26+
await waitForNextTask();
27+
28+
expect(connection.mutate).toHaveBeenCalledTimes(2);
29+
expect(connection.mutate).toHaveBeenCalledWith([7, 8, 9]);
30+
});
31+
32+
it('flushes mutations', async () => {
33+
const connection = createRemoteConnectionSpy();
34+
const batchingConnection = new BatchingRemoteConnection(connection);
35+
36+
batchingConnection.mutate([1, 2, 3]);
37+
batchingConnection.flush();
38+
39+
expect(connection.mutate).toHaveBeenCalledOnce();
40+
expect(connection.mutate).toHaveBeenCalledWith([1, 2, 3]);
41+
42+
await waitForNextTask();
43+
44+
// ensure it wasn't called again
45+
expect(connection.mutate).toHaveBeenCalledOnce();
46+
batchingConnection.mutate([4, 5, 6]);
47+
48+
await waitForNextTask();
49+
50+
expect(connection.mutate).toHaveBeenCalledTimes(2);
51+
expect(connection.mutate).toHaveBeenCalledWith([4, 5, 6]);
52+
});
53+
54+
it('enqueues the batch function only once while items are in the queue', async () => {
55+
const connection = createRemoteConnectionSpy();
56+
const batch = vi.fn();
57+
const batchingConnection = new BatchingRemoteConnection(connection, {
58+
batch,
59+
});
60+
61+
batchingConnection.mutate([1, 2, 3]);
62+
batchingConnection.mutate([4, 5, 6]);
63+
expect(batch).toHaveBeenCalledOnce();
64+
65+
const batchCallback = batch.mock.calls[0][0];
66+
batchCallback();
67+
68+
batchingConnection.mutate([7, 8, 9]);
69+
expect(batch).toHaveBeenCalledTimes(2);
70+
});
71+
});
72+
73+
async function waitForNextTask() {
74+
const channel = new MessageChannel();
75+
const promise = new Promise((resolve) => {
76+
channel.port1.onmessage = resolve;
77+
});
78+
channel.port2.postMessage(null);
79+
80+
await promise;
81+
}
82+
83+
function createRemoteConnectionSpy(): MockedObject<RemoteConnection> {
84+
return {
85+
mutate: vi.fn(),
86+
call: vi.fn(),
87+
};
88+
}

0 commit comments

Comments
 (0)