Stream is only sent after it has ended?
Closed this issue · 12 comments
I am trying to test your package, but it seems to be sending html after all promises have been resolved? Is it an issue with fastify, because I used to this kind of stuff with express. I also see you have asked same question here fastify/help#417. Have you been able to solve this issue?
Thanks
@jcbbb I just tested on my side and things seem to be working as expected. Do you have a sample of the code that's breaking?
Is it an issue with Fastify?
No Fastify works as expected.
I also see you have asked same question here fastify/help#417. Have you been able to solve this issue?
Yes, I was able to solve the issue. The problem was that I was sending the response stream only after I had pushed data into the stream, which is not the right order. The correct way is first send the stream then start pushing data into it.
Have a look at the code where I'm doing that:
https://github.com/grommett/fastify-chunk-view/blob/main/index.js#L21
Are you putting a Promise in the chunk array? If so, that might be your problem.
From the docs:
The fastify-chunk-view plugin takes an array of chunks and sends them to the client in that order. A chunk can be:
A string
A function that returns a string
An async function that returns a string
A Readable stream
I was putting a function that returns a promise, just like the productList example you have provided. I am not by my laptop right now, but I can double-check when I get home. Is the example in the readme working for you?
Hi @jcbbb the example in the Readme is working for me 🤷♂️ . I am only guessing at this point, but maybe you are calling the function instead of just passing the reference when adding it to the array?
// This won't work
reply.chunkView([asyncFunction()]
// This will
reply.chunkView([asyncFunction]
Also, when you get back to you computer one more question. In the final HTML output do you see
<!-- No strategy found for chunk -->
const products = [
{
title: "Macbook pro",
},
{
title: "Asus zenbook",
},
{
title: "Asus ROG",
},
];
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
async function getProducts() {
await wait(2000);
return `<ul>${products.map((product) => `<li>${product.title}</li>`).join("")}</ul>`;
}
const app = fastify({ logger: true });
app.get('/', (req, res) => {
res.chunkView(['<p>This should render immediately.</p>', getProducts, '<p>This is should render after getProducts completed.</p>'])
})
Hey @grommett, this is the code I am using, I am getting response only after 2 seconds. Have you tried delaying your getProducts example?
const app = express();
app.get("/", async (req, res) => {
res.write("<p>This should render first</p>");
const products = await getProducts();
res.write(products);
res.write("<p>This should render after products</p>");
res.end();
})
This, on the other hand, works as expected.
And your latest commit shows my exact problem 😄. It's only rendering after 1 second delay that you have added.
I can't reproduce on my side. What version of node are you using? Running the code sample you provided, with imports etc with Node v16
in Chrome, I see:
- This should render immediately
- Two seconds pass...
- The product list is rendered to the browser
Here is the code I'm running on my side:
const fastify = require('fastify');
const fastifyChunkView = require('fastify-chunk-view');
const products = [
{
title: 'Macbook pro',
},
{
title: 'Asus zenbook',
},
{
title: 'Asus ROG',
},
];
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
async function getProducts() {
await wait(2000);
return `<ul>${products.map((product) => `<li>${product.title}</li>`).join('')}</ul>`;
}
const app = fastify({ logger: true });
app.register(fastifyChunkView, {});
app.get('/', (req, res) => {
res.chunkView([
'<p>This should render immediately.</p>',
getProducts,
'<p>This is should render after getProducts completed.</p>',
]);
});
app.listen(3000, (err) => {
if (err) throw err;
// eslint-disable-next-line no-console
console.log(`server listening on ${app.server.address().port}`);
});
Oh shit, I found the problem. I was using browser-sync for livereloading browser, and I guess it does not work with streaming. When I started server without it, it started working! 😄
Sorry to disturb you, both your package and fastify was fine)
Glad to hear it works for you