And it’s great because it allows web pages to act like local software in terms of responsive and seamless interaction.
Any experienced web developer will tell you that it also sucks because the code required to drive those smooth interactions is a morass of callbacks and variable scopes that’s nearly impossible to debug or refactor.
How Do Browsers Work?
Here’s how browsers work, in a nutshell.
- Retrieve Response from Server
- Parse HTML to construct the DOM tree
- Render tree construction
- Layout of the Render Tree
- Painting the Render Tree
In simple terms, after the DOM has been rendered according to the style rules, it then only repaints things as necessary.
For example, it will repaint a link that you’re hovering over so it can change color. A slightly more expensive operation is a reflow, which means something substantial has changed that may require elements on the page to actually move around, changing the layout (step 4). That might be triggered by something as simple as a link turning bold when you hover over it, or as complex as an ajax call that replaces the contents of an element with totally new content.
Still, a reflow is much cheaper than a full refresh, because only a small part of the page needs to be replaced, and almost no additional requests are necessary (for things like stylesheets and layout images).
By setting this link to rel=”No-Refresh” you’re telling the browser that this link isn’t really a whole new thing, it’s just a variation of the current page. In other words, the browser doesn’t need to dump the current page and reload everything, because the changes to the page will be similar to a reflow.
Therefore, on a
no-refresh link, the browser will not reload the page. Instead it will:
- Internally fetch the target URI
- Perform a diff of the response body against the current DOM
- Construct only the part of the DOM that has changed
- Inject the changed content, and trigger a reflow of the document just as any other DOM manipulation
The user experience will be identical to an ajax call, but the code is much different. Here’s an example of the best case scenario, and I’ll even use jQuery to make it even cleaner:
This part is complicated, but essentially you have to detect an xmlhttprequest or pass in an extra param to let the server know you’re making an ajax request. That way you can return the part of the page you want, instead of the entire page.
The misdirection involved here, especially when using a framework like Rails, can get kind of hairy. Expect to complicate your controller action, and break your view into partial chunks so you can render them separately.
There are a few options for error handling, but the most obvious is just to load anything but a status 200 response as a normal page (which means showing the server error page). That can be the default.
A more elegant solution is to handle the
noRefreshError browser event. The event object could return all the request
information so you can handle different types of errors depending on the request URI.
It’s not the most elegant, but here’s an idea of how it would look:
Which would pretty readily be encapsulated as something like:
Remember that this system would automatically handle rendering error messages due to a user error, like trying to delete something without sufficient permission. That’s a 200 response, and would be handled normally. Only when the server failed to return a successful response would you have to handle the error.
no-refresh. Since a
no-refresh link would not update the browser’s URL field, it’s important that sites can only call a no-refresh link
from within the same domain.
Load Time & Server Load
This method sacrifices some page speed because it requires the server return everything, not just the chunks. It also requires a new diff operation between the current DOM and the new DOM instead of manual insertion of the changed elements.
Benchmarks would have to be performed, but I suspect the extra load would be negligible, especially considering the browser-level optimizations that become possible.
You also save programmer cycles because you eliminate fairly large and generally flaky areas of code from all web applications that use this technology.
It’s also possible to shim this behavior. The most difficult part of both the browser and shim implementations will be the diff and injection portions, but both are very doable. I’m looking for feedback on the idea, and once I have a robust concept, I can write the shim a a Proof of Concept. Then in only 20 or 30 years of committee approvals, we can have full browser adoption!