# Qwik Content Streaming ## Overview Let's assume you have a slow service that retrieves a Book. How can we stream the content of the page before the Book is retrieved? ## Code ```typescript= interface Book { title: string; author: string; } export const onGet = () => { await delay(2000); // Create artificial delay for a response return { title: 'Crossing the Chasm', author: 'Geoffrey A. Moore', } } export default component$(() => { const bookResource = useResource<Book>(); return ( <Resource resource={bookResource} onPending={() => <span>loading...</span>} onRejected={(e) => <span>Error: {e}</span>} onResolved={(book) => <span>{book.title} by {book.author}</span>} /> ); }); ``` ## Server Behavior During server rendering Qwik will wait for `bookResource` to be resolved before rendering the `onResolved` branch. ## Client Behavior On client, `<Resource>` will render `onPending` and then once `bookResource` is resolved it will re-render `onResolved` content. ## PROPOSAL: New Streaming Behavior 1. Server can start streaming HTML immediately. 2. When it gets to `<Resource>` the rendering can either: - Current behavior: 1. wait until `bookResource` is resolved and continue rendering. - Proposed behavior: 1. wait some time X and if `bookResource` is not resolved by that time (configurable) render the `onPending` branch and continue rendering. 2. When the page is fully rendered, Qwik needs to generated the state of the app in `<script type="qwik/json">`.But now we have a problem, `bookResource` is not yet resolved, so the best we can do is to serialize that `bookResource` is a promise which still has not resolved. So we serialized on-resolved promise reference. 3. We render `</body>`, but NOT `</html>`, instead we keep the connection open and wait for `bookResource` to resolve. At this point the browser can fully render the application and is interactive, but the connection is still open to server. 4. When `bookResource` resolves on the server, the server emits something like this once: ```html <script> window.qwikResolvePromise = function(promiseId, data) { qwikPromiseResolve[promiseId] = data; } window.qwikPatchResourceHTML = function(promiseId, html) { document. querySelector('[q\\:promise="'+promiseId+'"]'). innerHTML = html; } </script> ``` and then this for each resolved promise. ```html <script> qwikResolvePromise( 'p9234', { title: 'Crossing the Chasm', author: 'Geoffrey A. Moore' } ); qwikPatchResourceHTML( 'r398824', '<span>Crossing the Chasm by Geoffrey A. Moore</span>' ); </script> ``` NOTE: that each promise can be used in more than one `<Resource>` so resolving and patching HTML may have one-to-many relationship and require independent functions. 5. Once all of the promises are resolved the server renders `</html>` and closes the connection. ### Benefits - The above approach basically gives us the ability to render a placeholder for the UI and come back to it once the promise is resolved in a streaming way. - A non-resolved promise can keep the connection to the client open until the promise resolves. - From streaming point of view we can stream HTML immediately. If data is not available we can render `loading...` indicator and continue streaming the rest of the content. Once the promise is resolved we can render out a "patch" that goes back and fixes the state as well as. - The `qwikloader` can resume the application before OR after the streaming ends as in both cases it is in consistent state and can correctly resume. - The DB request can be triggered immediately without waiting for the data to be resolved.