Replies: 3 comments 9 replies
-
@remorses You can actually make this work with a little bit of wrapping. Here is the server snippet with the wrapper: 'use server'
const sleep = (t: number) => new Promise(r => setTimeout(r, t))
export type StreamResponseChunk<T> = {
iteratorResult: IteratorResult<T>
next?: Promise<StreamResponseChunk<T>>
}
async function streamChunk<T>(generator: AsyncGenerator<T>) {
const next = generator.next()
return new Promise<StreamResponseChunk<T>>((resolve, reject) => {
next.then(res => {
if (res.done) resolve({ iteratorResult: res })
else resolve({ iteratorResult: res, next: streamChunk(generator) })
})
next.catch(error => reject(error))
})
}
function streamResponse<T, P extends any[]>(createGenerator: (...args: P) => AsyncGenerator<T>) {
return (...args: Parameters<typeof createGenerator>) => {
const generator = createGenerator(...args)
return streamChunk<T>(generator)
}
}
export const generateData = streamResponse(async function* (a: number, b: string) {
for (let i = 0; i < 10; i++) {
await sleep(1000)
yield a + b + i
}
}) Here is the client side with 'unwrapper': 'use client'
import { useCallback } from 'react'
import * as api from './api/test'
function iterateStreamResponse<T>(streamResponse: Promise<api.StreamResponseChunk<T>>) {
return {
[Symbol.asyncIterator]: function () {
return {
current: streamResponse,
async next() {
const { iteratorResult, next } = await this.current
if (next) this.current = next
else iteratorResult.done = true
return iteratorResult
}
};
}
};
}
function Streams() {
const run = useCallback(async () => {
try {
const start = Date.now()
for await (const value of iterateStreamResponse(api.generateData(1, '1'))) {
console.log('Elapsed: ', Date.now() - start, ' Got: ', value)
}
} catch (error) {
console.error(error)
}
}, [])
return (
<button onClick={run}>
Start the show!
</button>
)
}
export default Streams |
Beta Was this translation helpful? Give feedback.
-
Still a goated response. Thanks! |
Beta Was this translation helpful? Give feedback.
-
Async genreators seem to work in server actions now! Just return the generator inside an async function |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Goals
for await of
Non-Goals
No response
Background
An example usage
Proposal
Async generators get converted to
ReadableSteam
of ndjson dataBeta Was this translation helpful? Give feedback.
All reactions