The technology has been around for a while and has had a rocky history to say the least. Some love it because of the often vastly improved page load times. Others hate it because of gotchas and having to track down weird event binding bugs persisting between page loads. There is no denying that it can make a big difference however as shown in the 100ms to Glass with Rails and Turbolinks post. But what if you can have essentially 0ms to Glass? That sounds better. Let’s do that.
How Turbolinks works
$(document).ready for pages loaded by Turbolinks. You have to use the events coming from Turbolinks instead. There are also issues with event handlers binding twice if you are not careful. Nonetheless, Turbolinks can be a huge improvement for many applications.
Instantclick is similar to Turbolinks because it also loads the pages with AJAX and replaces the body on page change. The major difference is that Instantclick starts loading the new page when a use hovers over the link. When the user then clicks the link it does the body replacement. In most cases this means that the new page is already loaded when the user clicks the link and the replacement happens immediately. The site will feel like it changed the page in an instant with no delay whatsoever for network load and such.
Instantclick has a test page where you can test your
speed skills. I tried it without “trying too hard” and this was the result:
As you can see, we have almost 200ms here to do something before the user expects something to happen on the screen. If a new page is loaded in this time and is ready in the chamber when the click goes through then the page will seem instant. Exciting stuff!
Combining ideas from Turbolinks and Instantclick
So now we loop back to Turbolinks. You can’t simply drop in Instantclick in a Turbolinks enabled application and call it a day. This won’t work. You can of course use only InstantClick but what if you want to use the other benefits from Turbolinks and still get the snappy performance?
Turns out that some clever people have thought of this already and opened up a discussion on Github. Further into the discussion is an implementation of this. That solution works fine but I wanted it to work without having to use jQuery since I don’t use it in my current project. Here is the version I made without the jQuery dependency.
You need to have hoverintent installed for this to work.
Again, this is not my code originally and the credit for this should go to grosser and Enalmada for coming up with the original solution.
This simply hooks into the
turbolinks:load event and will run on every page change after Turbolinks has done its thing. It will loop all the anchor tags on the site, ignore all the ones not using Turbolinks and then add the desired behavior to all of them. The use of hoverintent is due to the fact that you probably don’t want to preload all pages when the user simply moves the cursor across the screen. Hoverintent will instead trigger events when the cursor movement has slowed down. You can fiddle with the sensitivity and the interval but I found that these settings worked for me.
The main part of the code is to insert a link at the end of the document whenever a user hovers over an enabled anchor tag. It takes advantage of a technique called Link prefetching. When a browser has finished loading a page it will automatically watch for links with
rel='prefetch and load them into the cache in the background. When these URLs are then requested they are simply fetched from the cache and loaded. Thus, the instant magical performance is achieved. The code will also make sure that it doesn’t insert duplicate links if the user hovers over the same tag again. It also makes sure that only local links will be prefetched.