流响应 Stream Response

将响应流传输到客户端。流传输是 h3 的一项强大功能。它允许您在获得数据后立即将其发送到客户端。这对于大文件或长时间运行的任务非常有用。

流传输很复杂,如果您不需要它,可能会成为一项开销。

创建流

要流传输响应,您首先需要使用 ReadableStream API 创建流:

ts
const steam = new ReadableStream()

为了举例,我们将创建一个启动函数,每 100 毫秒发送一个随机数。1000 毫秒后,它将关闭流:

ts
let interval: NodeJS.Timeout
const stream = new ReadableStream({
  start(controller) {
    controller.enqueue('<ul>')

    interval = setInterval(() => {
      controller.enqueue(`<li>${Math.random()}</li>`)
    }, 100)

    setTimeout(() => {
      clearInterval(interval)
      controller.close()
    }, 1000)
  },
  cancel() {
    clearInterval(interval)
  },
})

发送流

在您的事件处理程序中,您需要设置响应标头以告知客户端我们正在发送流。否则,它将等待响应完成后再呈现它:

ts
import { defineEventHandler } from 'h3'

app.use(
  defineEventHandler(async (event) => {
    setResponseHeader(event, 'Content-Type', 'text/html')
    setResponseHeader(event, 'Cache-Control', 'no-cache')
    setResponseHeader(event, 'Transfer-Encoding', 'chunked')

    return null
  }),
)

然后,您可以使用“sendStream”实用程序发送流:

ts
import {
  createApp,
  defineEventHandler,
  sendStream,
  setResponseHeader,
} from 'h3'

export const app = createApp()

app.use(
  defineEventHandler((event) => {
    setResponseHeader(event, 'Content-Type', 'text/html')
    setResponseHeader(event, 'Cache-Control', 'no-cache')
    setResponseHeader(event, 'Transfer-Encoding', 'chunked')

    let interval: NodeJS.Timeout
    const stream = new ReadableStream({
      start(controller) {
        controller.enqueue('<ul>')

        interval = setInterval(() => {
          controller.enqueue(`<li>${Math.random()}</li>`)
        }, 100)

        setTimeout(() => {
          clearInterval(interval)
          controller.close()
        }, 1000)
      },
      cancel() {
        clearInterval(interval)
      },
    })

    return sendStream(event, stream)
  }),
)

打开浏览器访问 http://localhost:3000,您应该会看到每 100 毫秒出现一次的随机数列表。

Magic! 🎉