Используйте Asynchronous ReadableStream с Response для возврата HTML из события выборки Service Worker - PullRequest
3 голосов
/ 19 июня 2020

Этот вопрос похож на мой другой вопрос , но учитывает асинхронный характер внутри 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/

1 Ответ

1 голос
/ 19 июня 2020

Похоже, что 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;
  })
...