2. WHO AM I?
• Sebastian Springer
• aus München
• arbeite bei Mayflower
• https://github.com/sspringer82
• @basti_springer
• Consultant,Trainer,Autor
3. Wie öffnet ihr eure Dev Tools
im Browser?
• Was sind Dev Tools?
• Tastenkombination
• Mausklick (maximal 2)
4. Was erwartet euch?
Best Practices: Wie kann ich Probleme von vornherein
vermeiden?
Performance Optimierung: Was mache ich, wenn meine
Applikation langsam ist?
5. Performance
Es gibt nicht die eine JavaScript Performance. Wie sich eine
Applikation benimmt, hängt von zahlreichen Komponenten ab.
Die wichtigsten sind Netzwerk, CPU, Memory und
Rendering.
11. Analyse
Meist weiß man, wo die Applikation langsam ist. Ansonsten
werden CPU, Memory, Rendering und Netzwerk überprüft.
Konkrete Messwerte für den späteren Vergleich festhalten.
Profile-Daten können gespeichert, geladen und verglichen
werden.
13. Bewertung
Meist findet man mehrere Problemstellungen, hat jedoch
nicht genügend Ressourcen. Also Kosten-Nutzen-
Abwägung durchführen.
Cheap Wins zuerst durchführen, gravierende Umbauten mit
wenig Benefits eher nicht durchführen.
Erwartete Verbesserung oder Zielmetrik festhalten.
16. Durchführung
Anpassung des Quellcodes. Es sollte auf jeden Fall ein
Versionskontrollsystem (git, svn) eingesetzt werden. So
können die Stände verglichen und falls nötig zurückgesetzt
werden.
Tests nicht vergessen!
18. Kontrolle
Die Messwerte der Analyse werden mit den aktuellen Werten
der Applikation verglichen.
Im Anschluss steht die Entscheidung, ob weitere
Verbesserungen erforderlich sind oder ob weitere
Maßnahmen keinen erheblichen Mehrwert bieten.
27. CPU
Prozessor-Ressourcen, die benötigt werden, um den
JavaScript-Quellcode auszuführen.
Die meiste Performance geht aber durch DOM-Operationen
verloren.
28. CPU
JavaScript Engines weisen zahlreiche Optimierungen auf.
Häufig liegen die Probleme nicht an der Ausführung des
JavaScript-Quellcodes.
30. Maschinencode
Generierung
point.x
# ebx = the point object
cmp [ebx,<hidden class offset>],<cached hidden class>
jne <inline cache miss>
mov eax,[ebx, <cached x offset>]
Gibt es für die Eigenschaft eine Hidden Class, wird diese
verwendet. Ansonsten wird der Cache Miss behandelt. Dann
wird der Wert für die Eigenschaft ausgeliefert.
31. Garbage Collection
Aufräumen des Speichers. Zwei Speicherbereiche. Mit
unterschiedlichen Algorithmen.
GC benötigt Zeit, hält die Applikation komplett an. Das kann
zu Ruckeln in Applikationen führen.
32. Timeline
Die Timeline der Chrome Developer Tools gibt einen ersten
Überblick über CPU und Memory Daten und ist ein guter
Ausgangspunkt für die Analyse von Performance-Problemen.
34. CPU
Das CPU-Profile gibt genaueren Aufschluss darüber,
welche Routinen wie viele Ressourcen benötigt haben. Drei
verschiedene Darstellungsarten:
- Chart: Flame Chart
- Heavy (Bottom up): Tablle mit den teuersten Routinen oben
- Tree (Top Down): Baumdarstellung
36. CPU - Chart
Eine Funktion hat immer die gleiche Farbe. Erleichtert die
Mustererkennung.
Simulieren Callstacks jeweils mit Verweis auf die
entsprechende Codestelle.
Name: Funktionsname
Self time: Zeit der Funktion selbst
Total time: Zeit der Funktion und aller Unterfunktionen
Aggregated self time: Summe der self time aller Aufrufe
Aggregated total time: Summe der total time aller Aufrufe
44. Heap Snapshot
• Summary: Zusammenfassung
• Comparison: Vergleich zweier Snapshots
• Containment: Übersicht über die Objektstruktur
• Statistics: Verteilung des Speichers auf
Objekttypen
Verschiedene Views:
Abbild des aktuellen Speichers.
45. Heap Snapshot
Shallow Size: Speicher, den ein Objekt selbst benötigt.
Retained Size: Speicher, den ein Objekt und die nur von ihm
referenzierten Objekte benötigen.
Distance: Kürzester Weg durch die Memory Hierarchie.
54. Best Practices
Was kann man bereits bei der Entwicklung beachten, um
Performance-Probleme zu vermeiden?
55. Webworkers
Komplexe Berechnungen verzögern die Ausführung und
Blockieren die Applikation.
Mit HTML5 kommen Webworker: Kindprozesse im Browser.
Kommunikation über Nachrichten.
Workerprozess hat Zugriff auf:
navigator, location, xhr, timing,
Kein Zugriff auf:
DOM, window, document, parent
56. Webworkers
var worker = new Worker('worker.js');
worker.postMessage('Hello Worker');
worker.addEventListener('message', function (data) {
console.log(data);
});
index.js
worker.js
self.addEventListener('message', function (data) {
self.postMessage('Hello Main');
});
57. Variablen und
Datenstrukturen
Lokale Variablen nutzen, ist schneller als Property-Zugriff
und Array-Zugriff.
Objekte und Properties cachen.
Je tiefer ein Array strukturiert ist, desto langsamer wird der
Zugriff.
58. Prototypen und Methoden
function Calculator() {
this.add = function () {}
}
function Calculator() {}
Calculator.prototype.add = function () {};
vs
Für jede Instanz wird ein neues Funktionsobjekt erzeugt und
eine neue Closure generiert, was alles Speicherplatz
benötigt.
59. Prototypen und Werte
function Calculator() {
this.a = 1;
this.b = {};
}
function Calculator() {
this.b = {};
}
Calculator.prototype.a = 1;
vs
Initialisierungslogik muss nicht jedes Mal durchlaufen werden.
60. Closures
Eine Closure ist eine Funktion und ihr erstellender Kontext.
Benötigt also für die Funktion und den erstellenden Kontext
Speicher.
Quelle für Memoryleaks.
DOM-Elemente zeigen auf Closures und umgekehrt. GC
kann nicht aufräumen.
Sobald eine Callback-Funktion registriert wird, kann sie nicht
durch den GC freigegeben werden. Callbacks sollten
deregistriert werden.
61. function async() {
var msg = 'Hello World';
setTimeout(function() {
console.log(msg);
}, 1000);
}
Inner Funktion mit Closure
function async() {
setTimeout(function() {
var msg = 'Hello World';
console.log(msg);
}, 1000);
}
Inner Funktion ohne Closure
function sayHello() {
var msg = 'Hello World';
console.log(msg);
}
function async() {
setTimeout(sayHello, 1000);
}
Statische Funktion
Schnell
Langsam
62. Closures
Zugriff auf Variablen wird langsamer durch zusätzliche
Scopes. Je weiter nach außen, desto langsamer wird es.
function createFunctionWithClosure() {
var b = 'b';
return function () {
var c = 'c';
a;
b;
c;
};
}
createFunctionWithClosure(); c > b > a
63. Kein with
Die Scope Chain wird modifiziert. Es wird teurer, auf Variablen
zuzugreifen.
var a, x, y;
var r = 10;
with (Math) {
a = PI * r * r;
x = r * cos(PI);
y = r * sin(PI / 2);
}
64. Browser Memory Leaks
Expando Properties: Beliebige Eigenschaften auf DOM-
Objekten ,die z.B. zirkuläre Referenzen halten können.
Obj A > Obj B > Obj A
Im besten Fall komplett vermeiden.
65. Arbeit in Schleifen
reduzieren
Jedes Statement in einer Schleife wird pro Schleifendurchlauf
ausgeführt.
Funktionsdefinitionen oder Ähnliches vermeiden.
Möglichst statischen Code außerhalb und wirklich nur das
Nötigste in der Schleife halten.
for (var i = 0; i < arr.length; i++) {}
var length = arr.length;
for (var i = 0; i < length; i++) {}
66. Rendering
DOM einfach und flach halten.
Möglichst wenige CSS Regeln.
Für komplexes Rendering - position: absolute oder position:
fixed
Einfache CSS Selektoren.
68. Unnötige Variablen
vermeiden
var name = firstname + ' ' + lastname;
console.log(name);
console.log(firstname + ' ' + lastname);
vs.
Jede Variable benötigt Speicherplatz. Der GC bekommt
Arbeit.
69. JavaScript spät laden
JavaScript im Fuß der Seite laden.
JavaScript möglichst asynchron laden.
Alternative ist <script defer=“true” src=“”></script>
JS wird nach dem Parsen geladen.
<script async src=“”></script>
JS wird parallel zum Parsen geladen.
71. Achtung
Keine Premature Optimization - die richtigen
Optimierungen erst, wenn man sie braucht.
Keine Mikrooptimierung
Der Quellcode soll lesbar und wartbar bleiben.