使用异步 ReadableStream 和 Response 从 Service Worker 的 fetch 事件返回 HTML

问题描述 投票:0回答:2

这个问题与我的其他问题类似,但考虑到了

ReadableStream
内部的异步性质。

这是我现在的测试代码:

const stream = new ReadableStream({
    start(c) {
        let i = 1
        const t = setInterval(test, 5e2)
        function test() {
            c.enqueue("<h1>Yellow!</h1>")
            if (i++ === 5) {
                clearInterval(t)
                c.close()
            }
        }
    }
})
event.respondWith(new Response(stream, {headers: {"content-type": "text/html"}}))

上面的代码不是由浏览器渲染的,我不知道为什么。 根据在线示例,它似乎应该有效。但它似乎没有读取任何

enqueue
项目。

请注意,在我的其他问题中,答案至少给出了第一个响应:

const createStream = () => new ReadableStream({
  start(controller) {
    controller.enqueue("<h1 style=\"background: yellow;\">Yellow!</h1>")
    controller.close()
  }
})

const secondStream = createStream().getReader();
secondStream.read()
  .then(({
    value
  }) => {

    return new Response(value, {
      headers: {
        "Content-Type": "text/html"
      }
    });

  })
  .then(response => response.text())
  .then(text => {
    console.log(text);
  });

这似乎是有道理的,因为它会立即读取所有内容,而不考虑流是否完成。

我使用过的资源:

https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream#Examples

https://philipwalton.com/articles/smaller-html-payloads-with-service-workers/

javascript service-worker
2个回答
2
投票

看起来

stream
喜欢将
Uint8Array
放入
controller.enqueue
方法中。

TextEncoder
的帮助下,你的示例可以工作。

const data = [
  {name: "Yellow", value: 'yellow'},
  {name: "Green", value: 'green'},
  {name: "Blue", value: 'blue'},
  {name: "Red", value: 'red'},
  {name: "Orange", value: 'orange'},
]

const encoder = new TextEncoder();

const stream = new ReadableStream({
    start(controller) {
        let i = 1
        const handle = setInterval(test, 5e2)
        function test() {
            const {name, value} = data[i - 1];
            controller.enqueue(encoder.encode(`<h1 style="color: ${value};">${name}!</h1>`))
            if (i++ === 5) {
                clearInterval(handle)
                controller.close()
            }
        }
    }
})

new Response(stream, {headers: {"content-type": "text/html"}})
  .text().then(text => {
    document.body.innerHTML = text;
  })


0
投票

使用更现代语法的类似示例(请注意,ReadableStream.from到目前为止仅在 Firefox、Node 和 Deno 中实现)。技巧仍然与 Jozef 的答案相同:使用

TextEncoder

const encoder = new TextEncoder()

const generator = async function* () {
  yield encoder.encode('a')
  yield encoder.encode('b')
  yield encoder.encode('c')
}

const res = new Response( ReadableStream.from(generator()) )

console.log(await res.text())

© www.soinside.com 2019 - 2024. All rights reserved.