Lazy-Loading von Disqus-Kommentaren

Avatar of Osvaldas Valutis
Osvaldas Valutis am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

In letzter Zeit habe ich mich mit der Optimierung der Leistung durch Lazy-Loading beschäftigt. Kürzlich habe ich darüber geschrieben, wie man Google Maps per Lazy-Loading lädt und wie man responsive Google AdSense-Anzeigen per Lazy-Loading lädt. Nun ist es Zeit für Disqus, einen Dienst zum Einbetten von Kommentaren auf Ihrer Website. Es ist ein großartiger Dienst. Er erspart die Kopfzerbrechen bei der Entwicklung eines eigenen lokalen Kommentarsystems, der Bekämpfung von Spam usw. Kürzlich habe ich an der Implementierung des Widgets in einem meiner Projekte gearbeitet.

Das Problem

Layout-bedingt spielen Kommentare meist eine untergeordnete Rolle. In vielen Fällen werden Kommentare von den Besuchern gar nicht gesehen, da sie nicht nach unten scrollen, bis sie dort sind. Aber wissen Sie was? Standardmäßig werden sie auf der Website geladen, egal was passiert. Der verschwendete Bandbreitenverbrauch ist ein Problem.

Werfen wir einen Blick auf die technische Implementierung, die von Disqus offiziell empfohlen wird

<div id="disqus_thread"></div>
<script>
  (function() {
    var d = document, s = d.createElement('script');
    s.src = '//username.disqus.com/embed.js';
    s.setAttribute('data-timestamp', +new Date());
    (d.head || d.body).appendChild(s);
  })();
</script>

Hier sagen sie: *"Platzieren Sie den folgenden Code dort, wo Disqus geladen werden soll."* Nehmen wir an, Sie sind ein guter Entwickler und fügen normalerweise alle <script src="..."></script>-Fragmente direkt vor dem schließenden Tag </body> ein. Dann beschließen Sie eines schönen Tages, Disqus-Kommentare auf Ihrer Website zu implementieren und platzieren den obigen Code irgendwo in der Mitte des Dokuments, wo der Kommentarbereich vorgesehen war.

Was passiert? Die allererste herunterzuladende JavaScript-Datei ist username.disqus.com/embed.js. Das bedeutet nicht unbedingt, dass sie zuerst heruntergeladen wird, aber sie ist die erste in der Reihe der JavaScript-Dateien, die die Aufmerksamkeit des Browsers erregt. Sollte der erste Platz nicht für die Haupt-JavaScript-Datei Ihrer Website reserviert sein? Es gibt viele Dinge (wie "schlafende" <button>s usw.), die schiefgehen können, wenn Ihre Haupt-JavaScript-Datei spät geladen wird, besonders wenn Sie damals bei der Entwicklung dieser Website nicht die Prinzipien der *graceful degradation* (dezenten Degradation) oder *progressive enhancement* (progressiven Verbesserung) befolgt haben.

Dies stört auch andere externe Ressourcen auf Ihrer Website, wie Bilder und CSS-Dateien. Stellen Sie sich vor, Sie nutzen ein Smartphone unter 2G-Netzwerkbedingungen und warten darauf, dass das Kommentar-Widget geladen wird, nur weil Sie wegen eines Katzenfotos gekommen sind.

Ich habe einen Test gemacht. Es stellt sich heraus, dass das Disqus-Widget mit null Kommentaren 2,49 MB wiegt! Eine Menge Netzwerkanfragen für JavaScript-, CSS-, Bild- und Schriftdateien, die in vielen Fällen die anderen, vielleicht kritischen Teile oder Funktionen Ihrer Website unnötig verlangsamen.

Disqus Kommentare: Kein Lazyload

Die Lösung: Kleines JavaScript-Plugin

Um Disqus per Lazy-Loading laden zu können, habe ich ein kleines JavaScript-Plugin entwickelt, das die Arbeit erledigt. Egal wo sich die Kommentarzone befindet, oberhalb oder unterhalb des Viewports, sie wird nicht geladen, wenn es keinen Grund dafür gibt.

Disqus Kommentare: Lazyloaded

Das Plugin selbst ist ein winziges Stück JavaScript. Ich habe zwei Versionen davon erstellt: Vanilla und jQuery. Ich habe es disqusLoader genannt. Sie können die Dateien hier herunterladen

So richten Sie es ein. Zuerst müssen Sie ein Element in HTML einfügen, an dem Sie den Kommentarbereich haben möchten.

<div class="disqus"></div>

Initialisieren Sie dann das Plugin wie folgt

// vanilla
disqusLoader( '.disqus', { scriptUrl: '//username.disqus.com/embed.js' });

// jQuery
$.disqusLoader( '.disqus', { scriptUrl: '//username.disqus.com/embed.js' });

"Das ist großartig, aber was ist mit der spezifischen Disqus-Konfiguration?", könnten Sie fragen. Sicher, es gibt ein weiteres Argument, das einen Disqus-nativen Wert akzeptiert. Es gibt auch ein paar weitere Plugin-spezifische Optionen

var options =
{
  scriptUrl: '//username.disqus.com/embed.js',
  /*
    @type: string (url)
    @default: none
    @required
    URL of Disqus' executive JS file. The value is memorized on the first function call
    and ignored otherwise because Disqus allows only one instance per page at the time.
  */

  laziness: 1,
  /*
    @type: int (>=0)
    @default: 1
    Sets the laziness of loading the widget: (viewport height) * laziness . For example:
    0 - widget load starts when at the least a tiny part of it gets in the viewport;
    1 - widget load starts when the distance between the widget zone and the viewport is no more than the height of the viewport;
    2 - 2x viewports, etc.
  */

  throttle: 250,
  /*
    @type: int (milliseconds)
    @default: 250
    Defines how often the plugin should make calculations during the
    processes such as resize of a browser's window or viewport scroll.
    250 = 4 times in a second.
  */

  /*
    @type: function
    @default: none
    Disqus-native options. Check Disqus' manual for more information.
  */
  disqusConfig: function()
  {
    this.page.title       = 'Page Title';
    this.page.url         = 'http://url.to/your-website';
    this.page.identifier  = 'unique-identifier';
  }
};

// vanilla
disqusLoader( '.disqus', options );

// jQuery
$.disqusLoader( '.disqus', options );

Probieren Sie es selbst aus

Demo ansehen

Sie können auch zum Projekt auf GitHub beitragen oder es verfolgen.

Disqus Callbacks

Callbacks sind großartig, weil Sie auf Benutzeraktionen reagieren können. Es gibt nur eine Art von Callback, die von Disqus offiziell dokumentiert ist. Wenn man sich den Quellcode der `embed.js`-Datei ansieht, kann man weitere vordefinierte Callback-Typen erkennen.

Disqus Kommentare: Callback-Liste im Quellcode von embed.js

Es scheint jedoch, dass nur zwei davon aktiviert sind: onNewComment und onReady. Das reicht für eine kleine, aber spürbare Verbesserung: eine Ladeanzeige.

Ergänzende Ladeanzeige

Das Laden des Disqus-Widgets besteht normalerweise aus zwei Teilen

  1. Laden der `embed.js`-Datei
  2. Laden der inneren Assets und Ausführen anderer Arten von Netzwerkanfragen

Disqus selbst kümmert sich um den 2. Schritt, den sie mit dem animierten Bild kennzeichnen. Aber was ist mit dem 1. Schritt? Es gibt viele Gründe, warum das Laden externer JavaScript-Dateien zehn Sekunden oder mehr dauern kann. Der Clou ist, dass dem Benutzer, unabhängig von den Netzwerkbedingungen, immer noch mitgeteilt wird, dass eine Kommentarfunktion auf Ihrer Website verfügbar ist. Benutzererlebnis steckt im Detail!

Disqus Kommentare: Eine ergänzende Ladeanzeige

Der technische Ansatz ist einfach: ein neues HTML-Element und eine JavaScript-Callback-Funktion, die hilft, das Element auszublenden.

<div class="disqus-placeholder">Loading comments...</div>
<div class="disqus"></div>
// vanilla
disqusConfig: function()
{
  this.callbacks.onReady = [function()
  {
    var el = document.querySelector( '.disqus-placeholder' );
    if( el.classList )
      el.classList.add( 'is-hidden' ); // IE 10+
    else
      el.className += ' ' + 'is-hidden'; // IE 8-9
  }];
}

// jQuery
disqusConfig: function()
{
  this.callbacks.onReady = [function()
  {
    $( '.disqus-placeholder' ).addClass( 'is-hidden' );
  }];
}
.disqus-placeholder.is-hidden { display: none; }

Sie können dies in Aktion auf der Demoseite sehen. Aber zuerst leeren Sie den Browser-Cache und drosseln die Netzwerkgeschwindigkeit.

Mehrere Instanzen oder Websites gleichzeitig?

Bei der Arbeit an der Technik habe ich ein paar wichtige Einschränkungen entdeckt, die heute bestehen…

Es ist unmöglich, mehrere Skriptquellen auf einer einzigen Seite zu haben

Sobald die Skriptdatei (z.B. //username.disqus.com/embed.js) geladen ist, wird die globale Variable window.DISQUS erstellt, aber nur, wenn sie nicht bereits zuvor gesetzt wurde (was ein schlechtes Zeichen ist, aber graben wir tiefer). Ich habe also einen Test gemacht. Ich habe das Widget aus dem Quellskript A initialisiert. Dann habe ich etwas Platz für die zukünftige Variable window.DISQUS = undefined geschaffen und das Widget der Quelle B initialisiert. Das Ergebnis war jedoch ein Durcheinander: Callback-Funktionen wurden mehrmals ausgelöst, die Kommentare wurden dupliziert usw. Offensichtlich ist der aktuelle Code von Disqus nicht darauf ausgelegt, mehrere Variablen zu unterstützen und individuell mit jeder Widget-Instanz zu operieren.

Es ist unmöglich, mehrere Widgets gleichzeitig auf einer einzigen Seite zu haben

Es gibt eine öffentliche JavaScript-Methode reset() verfügbar im Objekt DISQUS. Wenn Sie technische Erfahrung mit Disqus haben, wissen Sie vielleicht, dass das Widget in ein Element eingefügt wird, das für die id den Wert disqus_thread hat. Ich habe einen Test mit zwei Elementen gemacht: Das Widget im ersten Element geladen, das ID-Attribut entfernt und es an das zweite Element angehängt. Schließlich habe ich die Reset-Funktion aufgerufen und erwartet, dass die zweite Instanz neben der ersten erscheint. Das Aufrufen der Funktion zum Laden einer neuen Instanz *zerstört* jedoch auch alle zuvor initialisierten Widgets. Leider ist Disqus heute nur für eine einzige Instanz zur gleichen Zeit konzipiert.

Es ist möglich, das Widget in Echtzeit neu zu laden

Es gibt eine gute Nachricht! Auch wenn es nicht möglich ist, mehrere Widget-Instanzen gleichzeitig zu haben, können Sie die alten immer noch zerstören und neue laden. Lassen Sie uns diese Theorie in die Praxis umsetzen, mit der wahrscheinlich typischsten Situation: Tabs. Alles, was Sie tun müssen, ist, das Plugin jedes Mal aufzurufen, wenn der neue Tab aktiviert wird.

<div class="tabcontent" data-disqus-id="venus" data-disqus-title="Venus"></div>
<div class="tabcontent" data-disqus-id="earth" data-disqus-title="Earth"></div>
<div class="tabcontent" data-disqus-id="mars" data-disqus-title="Mars"></div>
// call this function every time a tab is clicked:

var initDisqus = function( content )
{
  disqusLoader( content,
  {
    scriptUrl:    '//username.disqus.com/embed.js',
    disqusConfig: function()
    {
      this.page.identifier  = content.getAttribute( 'data-disqus-id' );
      this.page.title     = content.getAttribute( 'data-disqus-title' );
    }
  });
}

Sie können dies in Aktion sehen oder den vollständigen Code auf der Demoseite einsehen.

Abschließende Gedanken

Dieser Beitrag handelt nicht von den Fehlern in Disqus. Es geht um die Fehler, die wir Entwickler machen. Unsere Welt ist voller Werkzeuge und es liegt an uns, wie wir sie nutzen. Auch wenn diese Werkzeuge bestimmte Probleme lösen, bringen sie normalerweise einige andere mit sich, wenn wir nicht die gebotene Sorgfalt walten lassen, wenn wir sie implementieren. Jede Entscheidung, den einfachsten Weg zu gehen, führt zu verlorenen Nutzern, sinkenden Konversionen und erhöhten Absprungraten. Sie können bereits Disqus, Google AdSense, Google Maps, Social Media Buttons per Lazy-Loading laden, Sie können auch eigene Techniken entwickeln und teilen. Seien Sie verantwortungsbewusst!