将异步 ReadableStream 与对 return HTML 的响应从 Service Worker 的获取事件中使用

Use Asynchronous ReadableStream with Response to return HTML from fetch event of Service Worker

这个问题类似于 但考虑到了 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"}}))

上面的代码不是由浏览器呈现的,我不确定为什么。 According to examples online 看起来应该可以。但它似乎没有阅读任何 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/

当您将 Uint8Array 放入 controller.enqueue 方法时,看起来 stream 喜欢。

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;
  })