-
Notifications
You must be signed in to change notification settings - Fork 68
Description
This is a low-priority idea that came up during some conversations about React streaming and general streaming designs to minimize the latency from requesting a page and receiving the first bytes. In some cases, getting unfinished HTML to the browser can have a measurable impact on page load experience.
The fundamental problem is demonstrated in the following main() function:
main() -> [
page_header(),
#panel { body = [ slow_to_compute_function() ] },
page_footer()
].In this function the body of the page takes a long time to generate, but the page header and footer are fast. Because we have to wait for main() to fully-complete before sending bytes to the browser this means that a browser sits waiting with no content.
A new function, wf:commit_content(HTML), could split up the rendering so that some HTML can be send while waiting for the rest of the function to compute.
main() ->
wf:commit_content(page_header()),
[
#panel { body = [ slow_to_compute_function() ] },
page_footer()
].In this version of the function we're communicating to nitrogen that the page header is ready to send to the client and there will be no more HTTP headers to follow; that everything else is the rest of the HTML document.
This is a fairly specific optimization but could have relevance even for Nitrogen projects, especially if they send the Nitrogen SCRIPT tags towards the top of the HTML. A browser currently has to wait for the full request to generate, then download it, then load the JS, then render the page.
If such a commit function existed, it would be possible to send the head of the HTML to the browser, including some of the page structure (e.g. navigation menu and logo/header) and, importantly, a list of JavaScript files and stylesheets to load. This gives the browser the opportunity to start fetching the JavaScript files and some images and stylesheets before the server is done creating the page.
I'm not sure if this can be done with all the supported backends, but I believe with cowboy at least it should be possible simply by sending data to the request process and then continuing to send another after main() finishes and returns. Once the initial committed payload sends, however, Nitrogen would have to ignore further calls to change the status code or send headers (wf:status_code/1 and wf:content_type/1 and wf:header/2 etc…).