NuGet Package of the Week - Courtesy Flush to flush buffers earlier and optimize time to first byte
Yes, really. It's got to be the best name for an open source library out there. It's a great double entendre and a great name for this useful little library. Perhaps English isn't your first language, so I'll just say that a courtesy flush gives the next person a fresh bowl. ;)
However, in the computer world "flushing a buffer" means forcing a buffer to be moved along, usually to a file or the network. Rather than holding data, you flush it, and move it along.
Nik from Glimpse has a small NuGet package called Courtesy Flush. He's got a good write-up on his blog.
It's a library to enable easier flushing of your buffer in ASP.NET MVC. From their site:
Why Flush Early?
Flushing early can provide performance improvements in web applications and has been a recomended best practice in the web performance community since 2007.
To find out more, check out Nik's blog where he covered the benefits of flushing early in two posts:
It builds on top of ASP.NET ActionFilters, which you can apply as attributes to your methods, or call within controllers.
Let's say that you have some server-side work that's very slow. That slow operation could hold up the rendering of your page until it completes. With a pre-flush like this you can get bytes onto the network and into the user's browser faster.
Here we render some information and get it out fast before we do something that's unavoidably slow.
public ActionResult About()
{
ViewBag.Title = DateTime.Now.Second;
this.FlushHead();
Thread.Sleep(2000);
ViewBag.Message = "Your application description page.";
return View();
}
Let's think about really specifically. It's important to know WHY you would want to do this and what exactly happens in the browser.
If you have a long running, but important process (we are pretending that Thread.Sleep(2000) is important) that takes 2 seconds, no HTML is sent to the browser. It's just waiting. The timeline looks like this:
See that blue line? We waited almost 5 seconds for the /about page, and while we were waiting, no Javascript and no CSS were being loaded. Why not? How could the browser know if it isn't seen the <head> of your HTML?
For an optimization, we could FLUSH the buffers that we have up to this point, putting the HTML that we have so far onto the network.
The Layout.cshtml we have a call to @Html.FlushHead() to get the the _Head.cshtml out and into the hands of the browser. It might look like this:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
@if (ViewBag.Description != null)
{
<meta name="description" content="@ViewBag.Description">
}
<title>@ViewBag.Title - My ASP.NET Application</title>
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/modernizr")
</head>
Here's what the SAME page looks like with the <head> flushed out first.
Look closely at the timeline. Here, I'll do it for you...below shows when we flushed early versus just waiting.
See how when we flushed the head it gave the browser enough information to stat loading some css and javascript we had in the <head?> The whole page took 5 seconds, but when we flush at least we get things going early, while when we don't flush we can't do a thing until the long running task finishes.
See the difference? Now, to be clear, don't blindly go and add optimizations without reading the code and understanding what's going on, but this is a nice tool for our ASP.NET toolbox.
We may see a similar but even more powerful technique in ASP.NET vNext that includes async flushes at multiple points, while updating the model as data is available.
Sponsor: Big thanks to Aspose for sponsoring the feed this week! Working with Files? Aspose.Total for .NET has all the APIs you need to create, manipulate and convert Microsoft Office documents and many other formats in your applications. Start a free trial today.
About Scott
Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.
About Newsletter
1. Chunked HTTP responses like this will be slightly larger, which makes sense as you are sending two HTTP responses rather than one. The following Stack Overflow question suggests this difference is in the region of 1-2%.
2. I'm not sure how caching will be affected by this. Presumably the browser caches both responses?
Now, to be clear, don't blindly go [snip]
Yeah, right. Not only will the retards copy your code verbatim without looking into the issue in any way, but when asked "why?" they'll reply "but Hanselman said so on his blog!".
I've lost faith in the developer "community" at large.
Sorry for the cynical perspective, your blog is great and I will definitely evaluate this technique before I implement it in any of my sites.
When I say empty, I mean the site header was loaded, but there is nothing interesting for the user to look at. Without flushing, as long as there is visual feedback for the user that a navigation is about to happen, it feels faster because there is less time spent looking at nothing.
Of course this is a little subjective. I do agree with Scott and the comments here, you need to review this for your system and decide what will be better / be perceived by your users.
As far as browser caching is concerned, nothing changes. The browser does still treats flushed content as one resource, and HTTP caching works the same as your used to.
@Stuart - You are correct. Always "Measure Twice, Cut Once" to make sure any optimization technique makes sense for your application. In your scenario, it sounds like flushing early is shedding light on a bigger performance problem that you may want to address as well.
@Daniel - This does not affect async at all. The two techniques are 100% compatible.
It did't seem to be possible to use sections in the _Head.cshtml with Flush without getting a compile error (.net 4.0/MVC 4)
And I spotted a typo: "a recomended best practice".
https://github.com/atlascode/asyncsections
This is slightly different because it flushes the entire static content early then uses javascript to move the dynamic content into the correct position in the dom when it arrives.
This seems like a cool implementation, flushing just the head is definitely simpler to work with :-)
Comments are closed.
For those who wanted to know the details of how this 'Flushing' actually works. It sends the HTTP header 'Transfer-Encoding: chunked' instead of 'Content-Length:12345'. This allows MVC to send the head section of your HTML to the browser sooner, thus allowing the CSS to be loaded quicker (Although your CSS should be cached and so this will only affect the first request) and the title of the page to appear in the browser quicker.
Does anyone have real life experiences of using this package?