Home

How to Load Disqus Comments Asynchronously (Bonus: And Why!)

What is Disqus?

Disqus is a drop-in commenting system that I’m using on Rap Genius. It solves these problems:

  1. Before Disqus, if you wanted comments on your website, you had to build the technology yourself (i.e., reinvent the wheel)

  2. Before Disqus, your comments were split across several identities — you might comment with your Google account on Blogger blogs, maybe you have a Wordpress account you use on Wordpress blogs, and when you come across a blog that’s neither Wordpress nor Blogger, maybe you leave an anonymous comment.

With Disqus, you have one account (your Disqus account) you can use at any site, which ties all your comments together and lowers the barrier to entry for commenting on new sites.

Disqus also has a few downsides:

  1. You have less control over the user's experience:
    1. You have to use a one-size fits all commenting form
    2. You have to use Disqus' copy -- e.g., "Add a comment", "2 comments and 3 reactions" (what's a reaction?). You can hack around this with clever Javascript, but it's still annoying
  2. You have to showcase the Disqus brand (thereby diluting your own brand)
  3. Disqus' officially supported method for loading its commenting form onto your site is very slow. Alleviating this slowness is the subject of this post.

The Problem

The web wasn’t designed with “mashups” in mind, and so importing content or functionality from another site into your page is always somewhat hacky. At a high level, here’s how Disqus works:

  1. Disqus gives you the URL of a remote Javascript file to include on your page
  2. This Javascript rewrites part of your page to create the Disqus commenting form -- by default it hooks into the <div> with the id disqus_thread
    • An inherent problem of the way the web is designed is that this Javascript can do anything it wants -- for example it could steal your users' cookie (the equivalent of stealing the password of the current site).

      To use Disqus you have to be super-confident both that they're not malicious and that they'll take the necessary precautions to prevent someone who is malicious from getting control of the Javascript they serve.

  3. To submit a comment, the commenting form POSTs to the Disqus server using an iframe in order to overcome the same origin policy. (Don't sweat this part too much -- it's not related to the post and I don't totally understand it myself)

The Javascript Disqus gives you to include looks something like this:

<script type="text/javascript" src="http://disqus.com/forums/rapexegesis/embed.js"></script>

Unfortunately, including this Javascript file directly on your page (as Disqus suggests) is bad for performance. This is because browsers download and execute included Javascript files synchronously, meaning that everything else has to wait while the file downloads and runs.

Because of this, it would be disastrous to include this Javascript file at the top of your page — doing so would mean that everything on the page (text, images, etc) would have to wait for the commenting form to load, which is bad because users can enjoy the page before the commenting form appears, and since it’s at the bottom, users aren’t likely to notice if it takes an extra 2-3 seconds to load.

Loading the comment form synchronously is a problem even if you include the Javascript at the bottom of your page because it will still delay any other Javascript that needs to run. For example, on Rap Genius, the Javascript that turns on the explanation tooltips couldn’t run until the Disqus comment form loaded — clearly not ideal

The Solution

A False Start

Ideally the Disqus comment form would load and execute asynchronously — i.e., without making everything after it wait.

jQuery abstracts away the details of loading remote scripts asynchronously with its $.getScript() method, so ideally we should be able to just replace the inline script tag with this jQuery code:

$(document).ready(function(){
  $.getScript("http://disqus.com/forums/rapexegesis/embed.js");
})

Unfortunately, this produces a blank white screen. What gives?

What’s Causing the Blank Screen?

Let’s have a look at the source of the script we’re loading (http://disqus.com/forums/rapexegesis/embed.js). This section in particular is interesting:

The Disqus Javascript is using document.write() to print the CSS necessary to style the Disqus comment box onto the page.

This is bad because document.write() can only be called before the DOM has loaded — after the DOM has loaded document.write() makes no sense because there’s no way to determine where the writing should take place. Because of this, the browser freaks out, and overwrites the entire document — in this case with a single style tag. This is what causes the blank screen.

Since the whole idea of our plan was to not block the loading of the DOM in order to load the Disqus comment form, Disqus' use of document.write() is a problem.

Why does Disqus use document.write() in the first place? Backwards compatibility — precisely because it’s so primitive, document.write() enjoys wide cross-browser support.

The Real Solution

Thankfully, Disqus leaves us an out — if we set the window.disqus_no_style variable to false, the Disqus script won’t use document.write() to load the styles, and our page won’t get overwritten:

window.disqus_no_style = true;
$.getScript("http://disqus.com/forums/rapexegesis/embed.js")

However, we need some way of loading these styles in order that the Disqus form not look terrible. I copied them into a separate stylesheet and included it.

Posted October 16th, 2009