gongxiangp2/lib/node-readable-stream.ts

62 lines
1.5 KiB
TypeScript

import { Readable } from 'node:stream'
export interface NodeReadableToWebStreamOptions {
onCancel?: (reason?: unknown) => void | Promise<void>
}
/**
* 将 Node.js Readable 转换为受 Web Stream 消费速度约束的流。
*
* 每次 pull 只向下游交付一个分块,避免 data 事件持续读取大文件、
* 而浏览器或代理来不及接收时在 Node 进程内堆积大量内存。
*/
export function nodeReadableToWebStream(
source: Readable,
options: NodeReadableToWebStreamOptions = {},
): ReadableStream<Uint8Array> {
const iterator = source[Symbol.asyncIterator]()
let finished = false
return new ReadableStream<Uint8Array>(
{
async pull(controller) {
if (finished) {
return
}
try {
const next = await iterator.next()
if (next.done) {
finished = true
controller.close()
return
}
const chunk = next.value
controller.enqueue(chunk instanceof Uint8Array ? chunk : Buffer.from(chunk))
} catch (error) {
finished = true
if (!source.destroyed) {
source.destroy()
}
controller.error(error)
}
},
async cancel(reason) {
finished = true
try {
await options.onCancel?.(reason)
} finally {
if (!source.destroyed) {
source.destroy()
}
}
},
},
{
highWaterMark: 1,
size: () => 1,
},
)
}