Obwohl JavaScript derzeit die höchste Anzahl von Entwicklern in seiner Community hat, bezogen auf jede andere Sprache der Welt; Es gibt viele Missverständnisse, oberflächliches Wissen, schlechte Annahmen unter den Community-Mitgliedern. In diesem Artikel haben wir eine Liste mit Tipps zusammengestellt, die Ihre Javascript-Anwendung schneller machen können.
In diesem Artikel geht es nicht um Dev-Ops und geht nicht auf Dinge wie das Minimieren Ihrer Dateien oder das Einrichten von Redis oder die Verwendung von Docker und Kubernetes ein, um Ihre Anwendung performant zu machen. In diesem Artikel geht es um die Codierung in JavaScript, um die Leistung zu verbessern.
Ich diskutiere hauptsächlich JavaScript, aber einige der Punkte beziehen sich nur auf node.js oder nur wenige auf clientseitiges JavaScript. Da die meisten JavaScript-Entwickler heutzutage jedoch Full-Stack sind, gehe ich davon aus, dass Sie diese leicht verstehen können.
Hintergrund
Die von Node.js V8 verwendete JavaScript-Engine kompiliert JavaScript in Maschinencode und führt ihn als nativen Code aus. Der Motor verwendet drei Komponenten, um zu versuchen, zu erreichen sowohl geringe Anlaufzeit als auch Spitzenleistung :
- Ein generischer Compiler, der JavaScript so schnell wie möglich in Maschinencode kompiliert.
- Ein Laufzeitprofiler, der verfolgt, wie viel Zeit für die Ausführung welcher Codeteile aufgewendet wird, und Code identifiziert, der optimiert werden könnte.
- Ein optimierender Compiler, der versucht, den zuvor identifizierten Code zu optimieren.
- Wenn die Annahmen des Optimierer-Compilers zu optimistisch waren, unterstützt er die Deoptimierung (deopt).
Der optimierende Compiler erzielt die beste Leistung, aber nicht der gesamte JavaScript-Code wird für die Optimierung ausgewählt: Es gibt Codemuster, deren Optimierung der optimierende Compiler verweigert.
Showtime jederzeit für Feuerstab aktivieren
Sie können verwenden dieses Ticket vom Google Chrome DevTools-Team als Leitfaden für Muster, die dazu führen, dass der Code von V8 nicht optimiert wird, mit möglichen Problemumgehungen. Einige Beispiele sind:
- Funktionen mit try-catch-Anweisungen.
- Erneutes Zuweisen eines Argumentwerts während der Verwendung von |_+_| Gebiet.
Obwohl der optimierende Compiler Ihren Code deutlich schneller ausführen lässt, drehen sich die meisten Leistungsverbesserungen in einer E/A-intensiven Anwendung darum, die Anweisungen neu anzuordnen und weniger teure Aufrufe zu verwenden, um mehr Operationen pro Sekunde zu ermöglichen, wie wir im Folgenden sehen werden Abschnitte.
Node.js bietet eine ereignisgesteuerte Architektur und eine blockierungsfreie E/A-API, die den Anwendungsdurchsatz und die Skalierbarkeit optimiert. Ein bemerkenswertes Merkmal von Node.js ist, dass es eine integrierte Bibliothek enthält, die es Anwendungen ermöglicht, ohne Software wie Apache HTTP Server oder IIS als Webserver zu fungieren. Sie sollten damit rechnen, dass sich immer mehr Webentwicklungsprojekte in Richtung einer einheitlichen Websprache verlagern, wobei Node.js die Nase vorn hat.
Angesichts der zunehmenden Allgegenwart von JavaScript und der Node.js-Plattform möchten Sie über die neuesten Optimierungen und Best Practices auf dem Laufenden sein. In diesem Artikel werfen wir einen Blick auf 7 Node.js-Leistungstipps, die unter der Haube ausgeführt werden sollten, um das Beste aus Ihren Anwendungen herauszuholen.
1. Implementieren Sie einen Reverse-Proxy-Server
Wir bei NGINX, Inc. sind immer etwas entsetzt, wenn wir Anwendungsserver sehen, die direkt dem eingehenden Internetverkehr ausgesetzt sind und im Kern leistungsstarker Websites verwendet werden. Dazu gehören viele WordPress-basierte Websites , beispielsweise sowie Node.js-Sites.
Node.js ist in größerem Maße als die meisten Anwendungsserver auf Skalierbarkeit ausgelegt, und seine Webserverseite kann viel Internetverkehr einigermaßen gut verarbeiten. Aber Webserving ist nicht die Daseinsberechtigung von Node.js – nicht das, wofür es wirklich entwickelt wurde.
Wenn Sie eine Website mit hohem Datenverkehr haben, besteht der erste Schritt zur Steigerung der Anwendungsleistung darin, einen Reverse-Proxy-Server vor Ihren Node.js-Server zu stellen. Dies schützt den Node.js-Server vor direkter Gefährdung durch den Internetverkehr und ermöglicht Ihnen eine große Flexibilität bei der Verwendung mehrerer Anwendungsserver, beim Lastenausgleich zwischen den Servern und beim Zwischenspeichern von Inhalten.
Setzen von NGINX vor ein bestehendes Server-Setup als a Reverse-Proxy-Server , gefolgt von zusätzlichen Anwendungen, ist ein Kernanwendungsfall für NGINX, implementiert von zig Millionen Websites weltweit.
Es gibt spezifische Vorteile für Verwenden von NGINX als Node.js-Reverse-Proxy-Server , einschließlich:
- Funktionen mit try-catch-Anweisungen.
- Erneutes Zuweisen eines Argumentwerts während der Verwendung von |_+_| Gebiet.
Notiz : Diese Tutorials erklären die Verwendung von NGINX als Reverse-Proxy-Server in Ubuntu 14.04 oder CentOS Umgebungen, und sie sind eine nützliche Übersicht für alle, die NGINX vor Node.js stellen.
2. Halten Sie den Code klein und leicht
Im Zeitalter von Mobilgeräten, in dem die Anwendungsleistung so entscheidend ist, ist es besonders wichtig, die Node.js-Codebasis so kompakt wie möglich zu halten, um die Latenz zu reduzieren und die Dinge zu beschleunigen. Ein Artikel bietet einige organisatorische Fragen, die es wert sind, in der Entwicklungsphase gestellt zu werden: Brauchen wir dieses Modul wirklich?, Warum verwenden wir dieses Framework? Lohnt sich der Overhead?, Können wir dies auf einfachere Weise tun? Eine andere Möglichkeit, die Anwendungsleistung zu optimieren, besteht darin, mehrere JS-Dateien zu verkleinern und zu einer zu verketten. Wenn Ihre App beispielsweise fünf JavaScript-Dateien enthält, stellt der Browser fünf separate HTTP-Anforderungen, um sie abzurufen. Um die Blockierung und Wartezeit zu vermeiden, besteht ein alternativer Ansatz darin, diese 5 Dateien zu verkleinern und zu einer optimierten zu verketten.
3. Verwenden Sie Node.js nicht zum Rendern statischer Assets
Ein wichtiger Leistungstipp wäre, Ihre statischen Assets wie CSS und Bilder auf einem Standard-Webserver wie Nginx zu rendern. Indem Sie Nginx so einrichten, dass Ihre statischen Inhalte bereitgestellt werden, reduzieren Sie die Belastung Ihrer Node.js-Instanz erheblich und steigern dabei Ihre Leistung.
4. Verwenden Sie clientseitiges Rendering
Dank leistungsstarker neuer clientseitiger MVC-Frameworks wie AngularJS und BackboneJS ist es für Entwickler viel einfacher geworden, dynamische One-Page-Apps zu erstellen. Diese Frameworks stellen APIs bereit, die JSON-Antworten direkt an den Client senden und nicht über den Server. Wenn Sie Node.js serverseitig rendern lassen, wird bei jeder Anfrage eine HTML-Seite zurückgesendet. Die Verwendung von clientseitigem Rendering in Ihrer Node.js-Umgebung kann erheblich Bandbreite sparen und die Latenz reduzieren.
5. CPU-Profiling
Es gibt mehrere CPU-Profiler, Node.js bietet einen sofort einsatzbereiten, der für die meisten Fälle gut genug ist. Die integrierter Node.js-Profiler nutzt die Profiler im V8 , den Stack in regelmäßigen Abständen während der Ausführung abtasten. Sie können eine V8-Tick-Datei erstellen, indem Sie das Flag –prof verwenden, um den Knoten auszuführen.
Anschließend können Sie die Ausgabe der Profiling-Sitzung verarbeiten, um die Informationen zu aggregieren und in etwas für Menschen lesbares umzuwandeln. mit dem –prof-process Flag :
arguments
Wenn Sie die bearbeitete Textdatei in einem Editor öffnen, erhalten Sie Informationen, die in Abschnitte unterteilt sind.
Suchen Sie in der Datei nach dem Abschnitt Zusammenfassung, der ungefähr so aussieht:
arguments
$ node --prof-process isolate-0xnnnnnnnnnnnn-v8.log > processed.txt
[Summary]:
ticks total nonlib name
20109 41.2% 45.7% JavaScript
23548 48.3% 53.5% C++
805 1.7% 1.8% GC
Die Werte stellen dar, wie viele der erfassten Beispiele in JavaScript / C++-Code / Garbage Collector aufgetreten sind und variieren je nach Code, den Sie profilieren. Dann können Sie zum entsprechenden Unterabschnitt der Datei (z. B. [JavaScript], [C++], …) navigieren, um die Details der Beispiele nach Vorkommen sortiert anzuzeigen.
Es gibt einen zusätzlichen Abschnitt in der verarbeiteten Datei der Profiling-Sitzung, [Bottom up (heavy) profile], der besonders nützlich ist. Es stellt Informationen über die primären Aufrufer jeder Funktion in einer baumartigen Struktur bereit. Nehmen Sie zum Beispiel den folgenden Ausschnitt:
4774 9.8% Shared libraries
356 0.7% Unaccounted
223 32% LazyCompile: *function1 lib/file1.js:223:20
Der Prozentsatz zeigt den Anteil eines bestimmten Anrufers an der Gesamtzahl seiner übergeordneten Anrufe an. Ein Sternchen vor einem Funktionsnamen bedeutet, dass Zeit in einer optimierten Funktion verbracht wird, während eine Tilde eine nicht optimierte Funktion bedeutet.
Im Beispiel wurden 99 % der Aufrufe von Funktion1 von Funktion2 getätigt, wobei Funktion3 gemäß dem Profiling-Beispiel für 100 % der Aufrufe von Funktion2 verantwortlich ist.
Seitenwechsel-Animation css
CPU-Profiling-Sitzungen und Flammendiagramme sind nützliche Werkzeuge, um zu verstehen, was sich die meiste Zeit im Stack befindet und welche Methoden CPU-Zeit verbrauchen, um niedrig hängende Früchte zu erkennen. Aber es ist wichtig zu verstehen, dass es Ihnen nicht die ganze Geschichte erzählt: Sie könnten einen höheren Grad an Parallelität in Ihrer Anwendung verhindern und die asynchronen IO-Vorgänge könnten die Identifizierung erschweren.
6. Implementieren Sie SSL/TLS und HTTP/2
Immer mehr Websites verwenden SSL/TLS, um alle Benutzerinteraktionen auf der Website zu sichern. Es ist Ihre Entscheidung, ob und wann Sie diesen Schritt machen, aber wenn und wann Sie dies tun, unterstützt NGINX den Übergang auf zwei Arten:
- Ein generischer Compiler, der JavaScript so schnell wie möglich in Maschinencode kompiliert.
- Ein Laufzeitprofiler, der verfolgt, wie viel Zeit für die Ausführung welcher Codeteile aufgewendet wird, und Code identifiziert, der optimiert werden könnte.
- Ein optimierender Compiler, der versucht, den zuvor identifizierten Code zu optimieren.
- Wenn die Annahmen des Optimierer-Compilers zu optimistisch waren, unterstützt er die Deoptimierung (deopt).
Zu den Implementierungsschritten, die Sie ausführen müssen, gehören das Aktualisieren der URL in der Node.js-Konfigurationsdatei, das Herstellen und Optimieren sicherer Verbindungen in Ihrer NGINX-Konfiguration und die Verwendung von SPDY oder HTTP/2, falls gewünscht. Das Hinzufügen von HTTP/2-Unterstützung bedeutet, dass Browserversionen, die HTTP/2 unterstützen, mit Ihrer Anwendung unter Verwendung des neuen Protokolls kommunizieren; ältere Browserversionen verwenden weiterhin HTTP/1.x.
Der folgende Konfigurationscode ist für einen Ghost-Blog mit SPDY, wie beschrieben Hier . Es enthält erweiterte Funktionen wie OCSP-Heften. Überlegungen zur Verwendung von NGINX für die SSL-Terminierung, einschließlich der OCSP-Stapling-Option, finden Sie unter Hier . Einen allgemeinen Überblick über dieselben Themen finden Sie unter Hier .
Sie müssen nur geringfügige Änderungen vornehmen, um Ihre Node.js-Anwendung zu konfigurieren und von SPDY auf HTTP/2 zu aktualisieren, jetzt oder wenn die SPDY-Unterstützung Anfang 2016 eingestellt wird.
221 99% LazyCompile: ~function2 lib/file2.js:70:57
7. Verwenden Sie den Echtzeit-App-Monitor, um Ihre App zu analysieren
Real Time Monitoring ist eine Drittanbieteranwendung, die es Administratoren ermöglicht, das System in Echtzeit bei Störungen oder Problemen zu warten und zu überwachen, die in Webanwendungen auftreten. Auf diese Weise können Sie sofort auf auftretende Fehler oder Bugs reagieren. In Node JS können Sie mit Newrelic, Stackify, Ruxit, LogicMonitor und Monitis Spuren und Aktivitäten schnell, übersichtlich und zuverlässig aufzeichnen. Mit dieser Überwachung können Sie detailliertere Probleme analysieren und herausfinden, insbesondere die Effektivität und den Zustand von node.js beim Zugriff durch mehrere Benutzer.
8. Web-Worker & Shared Buffer
JavaScript ist Single-Thread. Der gleiche Thread wird für die Ereignisschleife verwendet. Ihre neue Anfragebehandlung in node.js und dom-Rendering im Browser wird also nicht parallel verarbeitet.
Wenn Sie also eine Aufgabe haben, die mehr Rechenzeit in Anspruch nimmt, sollten Sie sie an einige Web-Worker delegieren. Im Fall von node.js gibt es keinen eingebauten Worker, aber Sie können ein npm-Modul verwenden oder einen neuen Prozess dafür erzeugen.
Ein häufiges Problem bei der Arbeit mit Mitarbeitern kann die Synchronisierung mit ihnen sein (ohne nach Abschluss eine Nachricht zu posten). Nun, |_+_| kann ein praktischer Weg dafür sein.
Offenbar ist SharedArrayBuffer seit dem 5. Januar 2018 standardmäßig deaktiviert; aber das (oder so ähnlich) ist schon drin Stufe 4 als ECMA-Vorschlag .
9. setImmediate über setTimeout(fn,0)
Dies ist nur ein Punkt für node.js-Entwickler. Viele der Entwickler verwenden weder setImmediate noch process.nextTick und gehen mit |_+_| einen Teil ihres Programms asynchron zu machen.
Nun, einige unserer Experimente zu setImmediate vs setTimeout(fn, 0) sagt, setImmediate kann bis zu 200 Mal (ja, mal, nicht nur Prozent) schneller sein als setTimeout(fn, 0).
Verwenden Sie also setImmediate häufiger als setTimeout; Seien Sie jedoch vorsichtig bei der Verwendung von process.nextTick, es sei denn, Sie verstehen, wie es funktioniert.
10. Systemaufruf
Libuv stellt eine plattformunabhängige API bereit, die von Node.js verwendet wird, um nicht blockierende IO auszuführen und Ihre Anwendungs-IO (Sockets, Dateisystem, …) wird letztendlich in Systemaufrufe übersetzt.
Die Planung dieser Systemaufrufe ist mit erheblichen Kosten verbunden. Sie sollten versuchen, die Anzahl der Systemaufrufe zu minimieren, indem Sie Schreibvorgänge gruppieren/stapeln.
Wenn Sie einen Socket oder einen Dateistream verwenden, können Sie die Daten von Zeit zu Zeit zwischenspeichern und leeren, anstatt jedes Mal einen Schreibvorgang auszuführen.
Sie können eine Schreibwarteschlange verwenden, um Ihre Schreibvorgänge zu verarbeiten und zu gruppieren. Die Logik für eine Schreibwarteschlangenimplementierung sollte etwa so aussehen:
- Funktionen mit try-catch-Anweisungen.
- Erneutes Zuweisen eines Argumentwerts während der Verwendung von |_+_| Gebiet.
Sie können eine Fenstergröße basierend auf der Gesamtpufferlänge oder der verstrichenen Zeit seit der Warteschlange des ersten Elements definieren. Das Definieren einer Fenstergröße ist ein Kompromiss zwischen der Latenzzeit eines einzelnen Schreibvorgangs und der durchschnittlichen Latenzzeit aller Schreibvorgänge. Sie sollten auch die maximale Anzahl der zu gruppierenden Schreibanforderungen und den Aufwand für die Generierung jeder Schreibanforderung berücksichtigen.
Im Allgemeinen möchten Sie Schreibvorgänge von Puffern in der Größenordnung von Kilobytes leeren. Wir haben einen Sweet Spot bei etwa 8 Kilobyte gefunden, aber Ihre Laufleistung kann variieren. Sie können die Implementierung im Client-Treiber für eine vollständige Implementierung einer Schreibwarteschlange.
Das Gruppieren oder Stapeln von Schreibvorgängen führt dank weniger Systemaufrufen zu einem höheren Durchsatz.
11. Node.js-Timer
Node.js-Timer , die die gleiche API haben wie Fenster-Timer in der Web-API, sind sehr nützlich, einfach zu planen / zu entplanen und werden im gesamten Ökosystem umfassend verwendet.
Daher ist es wahrscheinlich, dass zu einem bestimmten Zeitpunkt in einer Anwendung eine große Anzahl von Zeitüberschreitungen geplant ist.
Ähnlich wie andere Hashed-Wheel-Timer , Node.js verwendet eine Hash-Tabelle und eine verknüpfte Liste um die Timer-Instanzen zu pflegen. Aber im Gegensatz zu anderen Wheel-Timern hat es keine Hash-Tabelle mit fester Länge, sondern schlüsselt jede Liste von Timern nach Dauer auf.
Wenn der Schlüssel vorhanden ist (ein Timer mit der gleichen Dauer existiert), wird er als O(1)-Operation an den Bucket angehängt.
Wenn kein Schlüssel vorhanden ist, wird ein Bucket erstellt und der Timer wird daran angehängt.
Vor diesem Hintergrund müssen Sie sicherstellen, dass Sie die vorhandenen Buckets wiederverwenden, um zu vermeiden, dass ein ganzer Bucket entfernt und ein neuer erstellt wird. Wenn Sie beispielsweise Gleitverzögerungen verwenden, sollten Sie das neue Timeout (setTimeout()) erstellen, bevor Sie das vorherige entfernen (clearTimeout()).
In unserem Fall von Planen des Leerlauf-Timeouts (Heartbeat) Bevor wir den vorherigen entfernen, stellen wir sicher, dass das Scheduling und Desplaning von Leerlauf-Timeouts O(1)-Operationen sind.
Abschluss
Das Erhöhen der Konfiguration Ihres Servers, das Hochskalieren und Verteilen der Dienste sind einige der sehr bekannten Prozesse, um Ihre Anwendung leistungsfähig zu machen.
Aber wenn Ihr Code Speicherlecks oder sequenzielle Verarbeitung verursacht; All diese Dev-Ops-Schritte können nicht verhindern, dass Ihr Server verlangsamt oder sogar abgestürzt wird.
wie man bao kauft
Daher müssen Sie beim Codieren (unabhängig von der Sprache) alle bewährten Verfahren, Grenzfälle und Leistungspunkte kennen.
Ursprünglich veröffentlicht von https://socialdribbler.com
==============================
Danke fürs Lesen :heart: Wenn dir dieser Beitrag gefallen hat, teile ihn mit all deinen Programmierfreunden! Folge mir auf Facebook | Twitter
Erfahren Sie mehr
☞ Der komplette Node.js-Entwicklerkurs (3. Auflage)
☞ Angular & NodeJS - Der MEAN Stack Guide
☞ NodeJS - The Complete Guide (inkl. MVC, REST APIs, GraphQL)
☞ Docker für Node.js-Projekte von einem Docker-Captain
☞ Einführung in MySQL mit Node.js - Lernen Sie MySQL mit Node zu verwenden!
☞ Node.js Absolute Beginners Guide - Node von Grund auf lernen
#javascript #node-js
socialdribbler.com
Node.js / Javascript-Leistungscodierungstipps, um Anwendungen schneller zu machen
Obwohl JavaScript derzeit die höchste Anzahl von Entwicklern in seiner Community hat, bezogen auf jede andere Sprache der Welt; Es gibt viele Missverständnisse, oberflächliches Wissen, schlechte Annahmen unter den Community-Mitgliedern. In diesem Artikel haben wir eine Liste mit Tipps zusammengestellt, die Ihre Javascript-Anwendung schneller machen können.