Skip to content

Instantly share code, notes, and snippets.

@EmNudge
Created April 20, 2024 20:41
Show Gist options
  • Save EmNudge/2a5353488a41b8ea543cf5b7e0f1d31b to your computer and use it in GitHub Desktop.
Save EmNudge/2a5353488a41b8ea543cf5b7e0f1d31b to your computer and use it in GitHub Desktop.
Out Of Order Streaming in Node.js
import { createServer } from "node:http";
const sleep = (ms) => new Promise((res) => setTimeout(res, ms));
const suspend = (placeholder, promise) => {
const id = "stream-" + Math.random().toString(32).slice(2);
const inserterTag = `<script
src="data:text/javascript,"
onload="window[&quot;${id}&quot;].replaceWith(this.previousElementSibling), this.remove()"
></script>`;
const p = promise.then((content) => `${content}${inserterTag}`);
p[Symbol.toPrimitive] = () =>
`<content-placeholder id="${id}">${placeholder}</content-placeholder>`;
return p;
};
async function* getStreamingChunks(strings, ...values) {
yield String.raw(strings, ...values);
const chunkPromises = values.filter((value) => value instanceof Promise);
const resolvers = [];
const promiseQueue = Array(chunkPromises.length)
.fill()
.map(() => new Promise((res) => resolvers.push(res)));
for (const chunkPromise of chunkPromises) {
chunkPromise.then((content) => resolvers.shift()(content));
}
for await (const resolvedChunk of promiseQueue) {
yield resolvedChunk;
}
}
createServer(async (_req, res) => {
res.writeHead(200, {
"Content-Type": "text/html",
"Transfer-Encoding": "chunked",
});
const chunks = getStreamingChunks`
<html>
<head>
<title>Hello Page!</title>
</head>
<body>
<header>This is the Header</header>
<main>
${suspend(
"<h1>This is going to change</h1>",
sleep(1000).then(() => "<h1>Hello World!</h1>")
)}
${suspend(
"<p>This is going to change</p>",
sleep(500).then(() => "<p>Hello this is a paragraph</p>")
)}
</main>
<footer>This is the footer</footer>
</body>
</html>`;
for await (const chunk of chunks) {
res.write(chunk);
}
res.end();
}).listen(8080);
@EmNudge
Copy link
Author

EmNudge commented Apr 20, 2024

Credit to LankyMoose and Kai for help with construction.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment