Lazy loading Disqus

Comments update

The comment system on this blog has been migrated to Isso. The code should still work but there is no longer a demo of it.

Disqus uses a lot of bandwidth (~691 KB with over 40 requests) which feels like a waste if the user never looks at the comments. It isn’t too bad though as most requests are cached, which helps if the user is looking at multiple pages, but it still isn’t ideal.

One way to improve the UX would be to have a “load comments” button so Disqus is not loaded unless the user wants to read / leave a comment. The downside to this approach is it means waiting around for the Disqus to load.

Another way to improve the UX is to wait and only load Disqus when the user scrolls near the comment section which seemed like a better idea. So I’ve created a small script to do that:

(function (doc, win) {
  var script;
  var isLoaded;
  var shortname;
  var element;
  var eventCallback;
  var threashold = win.innerHeight * 0.75;

  if (element) {
    addEventListener("scroll", eventCallback);
    addEventListener("resize", eventCallback);
  }

  function throttle(fn, delay) {
    var lastCalled = 0;
    var timeout;

    return function () {
      var now = +new Date();
      var remaining = delay - (now - lastCalled);
      var args = arguments;

      clearTimeout(timeout);

      if (remaining > 0) {
        timeout = setTimeout(function () {
          lastCalled = now;
          fn.apply(null, args);
        }, remaining);
      } else {
        lastCalled = now;
        fn.apply(null, args);
      }
    };
  }

  function isPassedThreashold() {
    var top = element.getBoundingClientRect().top;
    return top - win.innerHeight <= threashold;
  }

  function lazyLoad() {
    if (!isLoaded && isPassedThreashold()) {
      removeEventListener("scroll", eventCallback);
      removeEventListener("resize", eventCallback);

      script = doc.createElement("script");
      script.async = true;
      script.src = "//" + shortname + ".disqus.com/embed.js";
      script.setAttribute("data-timestamp", +new Date());

      element.innerHTML = "Loading comments...";

      (doc.head || doc.body).appendChild(script);

      isLoaded = true;
    }
  }

  win.disqusLazy = function (opts) {
    opts = opts || {};
    shortname = opts.shortname;
    eventCallback = throttle(lazyLoad, opts.throttle || 100);
    element = opts.element || doc.getElementById("disqus_thread");
    threashold = opts.threashold || win.innerHeight * 0.75;

    if (element) {
      addEventListener("scroll", eventCallback);
      addEventListener("resize", eventCallback);
    }
  };
})(document, window);

And minified with Closure compiler:

(function(e,f){function r(a,t){var g=0,k;return function(){var h=+new Date,l=t-(h-g),m=arguments;clearTimeout(k);0<l?k=setTimeout(function(){g=h;a.apply(null,m)},l):(g=h,a.apply(null,m))}}function u(){!n&&c.getBoundingClientRect().top-f.innerHeight<=p&&(removeEventListener("scroll",b),removeEventListener("resize",b),d=e.createElement("script"),d.async=!0,d.src="//"+q+".disqus.com/embed.js",d.setAttribute("data-timestamp",+new Date),c.innerHTML="Loading comments...",(e.head||e.body).appendChild(d),
n=!0)}var d,n,q,c,b,p=.75*f.innerHeight;c&&(addEventListener("scroll",b),addEventListener("resize",b));f.g=function(a){a=a||{};q=a.h;b=r(u,a.j||100);c=a.element||e.getElementById("disqus_thread");p=a.i||.75*f.innerHeight;c&&(addEventListener("scroll",b),addEventListener("resize",b))}})(document,window);

807 bytes or 464 bytes gzipped.

Usage

The script add a disqusLazy method which takes an options object with the options:

disqusLazy({
  /**
   * Optional - Threashold in pixels
   *
   * How many pixels left to scroll before should
   * load Disqus (defaults to 3/4 of the viewport)
   */
  // threashold: win.innerHeight * .75,

  /**
   * Optional - Number of miliseconds to delay
   * between checks
   *
   * Defaults to 100ms.
   */
  // throttle: 100,

  /**
   * Optional - The element to apply the threashold to
   *
   * Defaults to the #disqus_thread element.
   */
  // element: doc.getElementById('disqus_thread'),

  /**
   * Required - Your Disqus shortname
   */
  shortname: "<your disqus shortname>",
});

Comments