Streaming Search Results
Back in part three, <await> showed you something unusual: while the server
renders, Marko streams. Everything above an <await> reaches the browser
immediately, the stream holds at that spot until the promise resolves, then
carries on. And when you rendered a page by hand, you met the server side of
it — template.render(input).pipe(res) pipes HTML into the response as it is
produced, instead of buffering the whole page first.
This lesson puts both to work on a classic demo: a search page whose results stream in over time, three at a time, down a single response that stays open. No polling, no websockets, no client JavaScript — just HTML arriving in pieces.
The setup (already written)
src/routes/index/index.tsis a plain Express handler that callstemplate.render({}).pipe(res). Because it streams, the browser can paint results the moment the first batch is ready, while the server is still working on the rest.src/routes/index/data.jsis a tiny fake search index. Intemplate.marko,loadPage(i)returns one page of three results a second later — standing in for a slow database.
Open src/routes/index/template.marko. It uses <define> to declare a
reusable snippet, Results, that awaits one page and renders it:
<define/Results|input|> <await|page|=loadPage(input.pageIndex)> <for|item| of=page> <div class="result">…</div> </for> <!-- and then? --> </await></>
<Results pageIndex=0/>Right now <Results pageIndex=0/> renders exactly one page — three results,
after one second — and stops there.
Your job: make it recurse
The trick to appending over time is that Results can render itself.
After a page’s results, start the next page — nested inside the current
<await>, so the next loadPage only fires once this one has resolved and
flushed.
- Where the
TODOis, add:<if=(input.pageIndex + 1 < TOTAL_PAGES)><Results pageIndex=(input.pageIndex + 1)/></if> - Reload the preview and watch: three results appear, then three more a second later, then three more… ten pages in all, down one response that stays open the entire time.
Each <await> flushes its batch in document order, and the next <Results>
sits just after it — so the browser paints each batch as it lands. That nesting
is the whole pattern: a chain of awaits, each one kicking off the next.
- Installing dependencies
- Starting dev server