Skip to content

Commit f060159

Browse files
committed
simplify create_async_iterator
1 parent 019c573 commit f060159

File tree

3 files changed

+62
-63
lines changed

3 files changed

+62
-63
lines changed

packages/kit/src/runtime/server/page/data_serializer.js

Lines changed: 42 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,8 @@ import {
1717
*/
1818
export function server_data_serializer(event, event_state, options) {
1919
let promise_id = 1;
20-
let count = 0;
2120

22-
const { iterator, push, done } = create_async_iterator();
21+
const { iterator, add } = create_async_iterator();
2322
const global = get_global_name(options);
2423

2524
/** @type {(nonce: string) => void} */
@@ -30,9 +29,8 @@ export function server_data_serializer(event, event_state, options) {
3029
function replacer(thing) {
3130
if (typeof thing?.then === 'function') {
3231
const id = promise_id++;
33-
count += 1;
3432

35-
thing
33+
const promise = thing
3634
.then(/** @param {any} data */ (data) => ({ data }))
3735
.catch(
3836
/** @param {any} error */ async (error) => ({
@@ -44,8 +42,6 @@ export function server_data_serializer(event, event_state, options) {
4442
* @param {{data: any; error: any}} result
4543
*/
4644
async ({ data, error }) => {
47-
count -= 1;
48-
4945
let str;
5046
try {
5147
str = devalue.uneval(error ? [, error] : [data], replacer);
@@ -60,13 +56,12 @@ export function server_data_serializer(event, event_state, options) {
6056
str = devalue.uneval([, error], replacer);
6157
}
6258

63-
push(
64-
`<script${await nonce}>${global}.resolve(${id}, ${str.includes('app.decode') ? `(app) => ${str}` : `() => ${str}`})</script>\n`
65-
);
66-
if (count === 0) done();
59+
return `<script${await nonce}>${global}.resolve(${id}, ${str.includes('app.decode') ? `(app) => ${str}` : `() => ${str}`})</script>\n`;
6760
}
6861
);
6962

63+
add(promise);
64+
7065
return `${global}.defer(${id})`;
7166
} else {
7267
for (const key in options.hooks.transport) {
@@ -124,57 +119,56 @@ export function server_data_serializer(event, event_state, options) {
124119
*/
125120
export function server_data_serializer_json(event, event_state, options) {
126121
let promise_id = 1;
127-
let count = 0;
128122

129-
const { iterator, push, done } = create_async_iterator();
123+
const { iterator, add } = create_async_iterator();
130124

131125
const reducers = {
132126
...Object.fromEntries(
133127
Object.entries(options.hooks.transport).map(([key, value]) => [key, value.encode])
134128
),
135129
/** @param {any} thing */
136130
Promise: (thing) => {
137-
if (typeof thing?.then === 'function') {
138-
const id = promise_id++;
139-
count += 1;
131+
if (typeof thing?.then !== 'function') {
132+
return;
133+
}
134+
135+
const id = promise_id++;
136+
137+
/** @type {'data' | 'error'} */
138+
let key = 'data';
140139

141-
/** @type {'data' | 'error'} */
142-
let key = 'data';
140+
const promise = thing
141+
.catch(
142+
/** @param {any} e */ async (e) => {
143+
key = 'error';
144+
return handle_error_and_jsonify(event, event_state, options, /** @type {any} */ (e));
145+
}
146+
)
147+
.then(
148+
/** @param {any} value */
149+
async (value) => {
150+
let str;
151+
try {
152+
str = devalue.stringify(value, reducers);
153+
} catch {
154+
const error = await handle_error_and_jsonify(
155+
event,
156+
event_state,
157+
options,
158+
new Error(`Failed to serialize promise while rendering ${event.route.id}`)
159+
);
143160

144-
thing
145-
.catch(
146-
/** @param {any} e */ async (e) => {
147161
key = 'error';
148-
return handle_error_and_jsonify(event, event_state, options, /** @type {any} */ (e));
162+
str = devalue.stringify(error, reducers);
149163
}
150-
)
151-
.then(
152-
/** @param {any} value */
153-
async (value) => {
154-
let str;
155-
try {
156-
str = devalue.stringify(value, reducers);
157-
} catch {
158-
const error = await handle_error_and_jsonify(
159-
event,
160-
event_state,
161-
options,
162-
new Error(`Failed to serialize promise while rendering ${event.route.id}`)
163-
);
164-
165-
key = 'error';
166-
str = devalue.stringify(error, reducers);
167-
}
168-
169-
count -= 1;
170-
171-
push(`{"type":"chunk","id":${id},"${key}":${str}}\n`);
172-
if (count === 0) done();
173-
}
174-
);
175164

176-
return id;
177-
}
165+
return `{"type":"chunk","id":${id},"${key}":${str}}\n`;
166+
}
167+
);
168+
169+
add(promise);
170+
171+
return id;
178172
}
179173
};
180174

packages/kit/src/utils/streaming.js

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@ function defer() {
1818
* Create an async iterator and a function to push values into it
1919
* @returns {{
2020
* iterator: AsyncIterable<any>;
21-
* push: (value: any) => void;
22-
* done: () => void;
21+
* add: (promise: Promise<any>) => void;
2322
* }}
2423
*/
2524
export function create_async_iterator() {
25+
let count = 0;
26+
2627
const deferred = [defer()];
2728

2829
return {
@@ -37,15 +38,20 @@ export function create_async_iterator() {
3738
};
3839
}
3940
},
40-
push: (value) => {
41-
deferred[deferred.length - 1].fulfil({
42-
value,
43-
done: false
41+
add: (promise) => {
42+
count += 1;
43+
44+
void promise.then((value) => {
45+
deferred[deferred.length - 1].fulfil({
46+
value,
47+
done: false
48+
});
49+
deferred.push(defer());
50+
51+
if (--count === 0) {
52+
deferred[deferred.length - 1].fulfil({ done: true });
53+
}
4454
});
45-
deferred.push(defer());
46-
},
47-
done: () => {
48-
deferred[deferred.length - 1].fulfil({ done: true });
4955
}
5056
};
5157
}

packages/kit/src/utils/streaming.spec.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,13 @@ import { expect, test } from 'vitest';
22
import { create_async_iterator } from './streaming.js';
33

44
test('works with fast consecutive promise resolutions', async () => {
5-
const iterator = create_async_iterator();
5+
const { iterator, add } = create_async_iterator();
66

7-
void Promise.resolve(1).then((n) => iterator.push(n));
8-
void Promise.resolve(2).then((n) => iterator.push(n));
9-
void Promise.resolve().then(() => iterator.done());
7+
add(Promise.resolve(1));
8+
add(Promise.resolve(2));
109

1110
const actual = [];
12-
for await (const value of iterator.iterator) {
11+
for await (const value of iterator) {
1312
actual.push(value);
1413
}
1514

0 commit comments

Comments
 (0)