Last active
December 11, 2024 13:52
-
-
Save domenic/ea5ebedffcee27f552e103963cf8585c to your computer and use it in GitHub Desktop.
Service worker stream transferring
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
const worker = new Worker("worker.js"); | |
self.onfetch = e => { | |
const transform = new TransformStream(); // creates an identity transform | |
e.respondWith(new Response(transform.readable)); | |
// Give the worker the writable end. An identity transform stream will just shuffle | |
// bytes written there into transform.readable. | |
worker.postMessage(transform.writable, [transform.writable]); | |
// transform.writable has now been transferred/neutered/detached. | |
// This means that transform.writable.getWriter() will never work anymore in this thread. | |
// However, the *creator* of transform.writable (i.e., the logic inside | |
// new TransformStream()) can still see data that is written to it. That logic | |
// will then shuffle it over to transform.readable. | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
self.onmessage = ({ data: writableStream }) => { | |
const writer = writableStream.getWriter(); | |
writer.write(new Uint8Array([1, 2, 3, 4])); | |
writer.close(); | |
// You can, of course, do the writing/closing asynchronously. | |
}; |
Are you performing any other fetches client side? fetch
event can be called multiple times for the document itself, icons, etc. You can include a query string in the URL requested , or use other means to identify the request where a Response()
with ReadableStream
passed is expected
if (event.request.url.includes('stream')) {
event.respondWith(
new Response(readable, {
cache: 'no-store',
headers: { 'Content-Type': 'application/octet-stream' },
})
);
console.log(readable);
}
`
@guest271314, no, I'm not. It's a test page and I'm doing only that request. For some reason, the way I'm handling it in the example above is incorrect. So it's not a request-matching issue. I do have a slightly more complex setup than above, so maybe some other things affect this.
@kettanaito Try passing a Uint8Array
to enqueue()
.
@guest271314, yes, that was the root cause! 🎉 I've come to discover it as well. You should transfer encoded data over ReadableStream
.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hey, @domenic. Thank you for this example.
Do you have any idea why responding with a ReadableStream from a service worker would render an unreadable response on the client?
Whenever I try to read this response on the client, I get a FetchError:
I apologize if this is a question indirectly related to the gist above but I could really use your advice. Thanks.
Answer
Use
new TextEncoder().encode('data')
before passing it to the stream.