BigPipe ist eine von Facebook entwickelte Technologie zur Optimierung der Ladegeschwindigkeit von Webseiten. Es gibt fast keine Artikel, die mit node.js im Internet implementiert wurden. Tatsächlich sind Implementierungen von BigPipe in anderen Sprachen, nicht nur mit node.js, im Internet selten. So lange nach dem Erscheinen dieser Technologie dachte ich, dass, nachdem zuerst der gesamte Webseiten-Frame gesendet wurde, eine oder mehrere Ajax-Anfragen verwendet wurden, um die Module auf der Seite anzufordern. Bis vor nicht allzu langer Zeit habe ich erfahren, dass das Kernkonzept von BigPipe darin besteht, nur eine HTTP-Anfrage zu verwenden, die Seitenelemente werden jedoch in der falschen Reihenfolge gesendet.
Es wird einfacher, wenn Sie dieses Kernkonzept verstanden haben. Dank der asynchronen Funktionen von node.js ist es einfach, BigPipe mit node.js zu implementieren. In diesem Artikel wird anhand von Beispielen Schritt für Schritt der Ursprung der BigPipe-Technologie und eine einfache Implementierung auf Basis von node.js erläutert.
Zur Veranschaulichung verwende ich Express. Wir wählen Jade als Vorlagen-Engine und verwenden nicht die (partielle) Untervorlagenfunktion der Engine, sondern den HTML-Code, nachdem die Untervorlage gerendert wurde die Daten der übergeordneten Vorlage.
Erstellen Sie zunächst einen Ordner „nodejs-bigpipe“ und schreiben Sie eine package.json-Datei wie folgt:
Führen Sie npm install aus, um diese drei Bibliotheken zu installieren. Consolidate wird verwendet, um den Aufruf von Jade zu erleichtern.
Lassen Sie uns zunächst das Einfachste ausprobieren, zwei Dateien:
app.js:
var app = express()
app.engine('jade', cons.jade)
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'jade')
app.use(function (req, res) {
res.render('layout', {
s1: „Hallo, ich bin der erste Abschnitt.“
, s2: „Hallo, ich bin der zweite Abschnitt.“
})
})
app.listen(3000)
views/layout.jade
Kopf
Titel Hallo Welt!
Stil
Abschnitt {
Rand: 20 Pixel automatisch;
Rand: 1 Pixel gepunktet grau;
Breite: 80 %;
Höhe: 150px;
}
Abschnitt#s1!=s1
Abschnitt#s2!=s2
Der Effekt ist wie folgt:
Als nächstes legen wir die beiden Abschnittsvorlagen in zwei verschiedene Vorlagendateien ab:
views/s1.jade:
views/s2.jade:
Fügen Sie einige Stile zum Stil von layout.jade hinzu
Ändern Sie den app.use()-Teil von app.js in:
Bevor wir sagten: „Verwenden Sie den HTML-Code, nachdem die Untervorlage als Daten der übergeordneten Vorlage gerendert wurde“, bedeutet dies: Die beiden Methoden temp.s1 und temp.s2 generieren zwei Dateien, s1.jade und s2.jade. HTML-Code und verwenden Sie diese beiden Codeteile dann als Werte der beiden Variablen s1 und s2 in layout.jade.
Die Seite sieht jetzt so aus:
Im Allgemeinen werden die Daten der beiden Abschnitte separat abgerufen – sei es durch Abfrage der Datenbank oder durch RESTful-Anfrage, wir verwenden zwei Funktionen, um solche asynchronen Vorgänge zu simulieren.
Auf diese Weise wird die Logik in app.use() komplizierter. Der einfachste Weg, damit umzugehen, ist:
Dies kann auch zu den gewünschten Ergebnissen führen, aber in diesem Fall dauert die Rückkehr volle 8 Sekunden.
Tatsächlich zeigt die Implementierungslogik, dass getData.d2 erst aufgerufen wird, nachdem das Ergebnis von getData.d1 zurückgegeben wurde, und zwischen den beiden besteht keine solche Abhängigkeit. Wir können Bibliotheken wie async verwenden, die asynchrone JavaScript-Aufrufe verarbeiten, um dieses Problem zu lösen, aber schreiben wir es einfach hier von Hand:
Dies dauert nur 5 Sekunden.
Vor der nächsten Optimierung haben wir die JQuery-Bibliothek hinzugefügt und den CSS-Stil in eine externe Datei eingefügt. Übrigens haben wir auch die Datei runtime.js hinzugefügt, die für die Verwendung der Jade-Vorlage auf der Browserseite erforderlich ist, die wir später verwenden werden . Führen Sie im Verzeichnis aus, das app.js enthält:
Und nehmen Sie den Code im Style-Tag in layout.jade heraus, fügen Sie ihn in static/style.css ein und ändern Sie dann das Head-Tag in:
In app.js simulieren wir die Download-Geschwindigkeit beider auf zwei Sekunden und fügen Folgendes hinzu:
vor app.use(function (req, res) {
Unsere Seite wird aufgrund externer statischer Dateien jetzt in etwa 7 Sekunden geladen.
Wenn wir den Kopfteil zurückgeben, sobald wir die HTTP-Anfrage erhalten, und die beiden Abschnitte dann warten, bis der asynchrone Vorgang abgeschlossen ist, bevor sie zurückkehren, verwendet dies den HTTP-Chunked-Transfer-Codierungsmechanismus. Solange Sie in node.js die Methode res.write() verwenden, wird der Header „Transfer-Encoding: chunked“ automatisch hinzugefügt. Während der Browser die statische Datei lädt, wartet der Knotenserver auf diese Weise auf das Ergebnis des asynchronen Aufrufs. Löschen wir zunächst diese beiden Zeilen im Abschnitt in layout.jade:
Wir müssen das Objekt { s1: …, s2: … } also nicht in res.render() angeben, und da res.render() standardmäßig res.end() aufruft, müssen wir dies manuell tun Nach Abschluss rendern Die Rückruffunktion verwendet die darin enthaltene Methode res.write(). Der Inhalt von „layout.jade“ muss nicht in der Callback-Funktion „writeResult()“ enthalten sein. Wir können beim Empfang dieser Anfrage zurückkehren. Beachten Sie, dass wir den Content-Type-Header manuell hinzugefügt haben
Bitte beachten Sie jedoch, dass dieser Effekt erzielt werden kann, da getData.d1 schneller ist als getData.d2. Mit anderen Worten: Welcher Block in der Webseite zuerst zurückgegeben wird, hängt vom asynchronen Aufrufergebnis der Schnittstelle ab, die zuerst zurückgegeben wird. Wenn wir getData auf 8 Sekunden setzen, wird Teil 2 zuerst zurückgegeben und die Reihenfolge von s1 und s2 wird umgekehrt. Das Endergebnis der Webseite entspricht nicht unseren Erwartungen.
Diese Frage führt uns schließlich zu BigPipe. BigPipe ist eine Technologie, die die Anzeigereihenfolge jedes Teils der Webseite von der Datenübertragungsreihenfolge entkoppeln kann.
Die Grundidee besteht darin, zunächst den allgemeinen Rahmen der gesamten Webseite zu übertragen und die Teile, die später übertragen werden müssen, durch leere Divs (oder andere Tags) darzustellen:
Dann schreiben Sie die zurückgegebenen Daten mit JavaScript
s2 wird ähnlich gehandhabt. Zu diesem Zeitpunkt werden Sie sehen, dass in der zweiten Sekunde der Anforderung der Webseite zwei leere gepunktete Kästchen erscheinen, in der fünften Sekunde der Teil 2 erscheint, in der achten Sekunde der Teil 1 erscheint und die Webseite erscheint Die Anfrage ist abgeschlossen.
Zu diesem Zeitpunkt haben wir eine Webseite fertiggestellt, die mit der einfachsten BigPipe-Technologie implementiert wurde.
Es ist zu beachten, dass das zu schreibende Webseitenfragment ein Skript-Tag hat. Ändern Sie beispielsweise s1.jade in:
Aktualisieren Sie dann die Webseite und Sie werden feststellen, dass die Warnung nicht ausgeführt wird und es Fehler auf der Webseite gibt. Überprüfen Sie den Quellcode und stellen Sie fest, dass der Fehler durch das Erscheinen von in der Zeichenfolge in verursacht wird
还要在 Layout.jade 把两个 Abschnitt 添加回来:
这里的思路是,需要pipe 的内容先用一个 span 标签占位,异步获取数据并渲染完成相应的HTML. 代码后Wenn Sie eine neue jQuery-App verwenden, verwenden Sie replaceWith und verwenden Sie die span-Funktion 。
本文的代码在 https://github.com/undozen/bigpipe-on-node并 hack 一下看看(其实应该可以用 gif 动画实现,但是我懒得做了).
关于 BigPipe 的实践还有很大的优化空间, 比如说, 要 Pipe 的内容最好设置一个触发的时间值, 如果异步调用的数据很快返回, 就不需要用 BigPipe, 直接生成网页送出Sie haben die Möglichkeit, BigPipe zu verwenden, indem Sie BigPipe verwenden Verwenden Sie die Datei node.js优化和实践方法,等到雪球网用上 BigPipe 以后再分享吧.