Developer Tip of the Month: " ExtJS Layout Performance mit ViewModels"

 ExtJS Layout Performance mit ViewModels

Problem

Komplexe ExtJS Apps haben oft irgendwann im Entwicklungszyklus mit Performanceproblemen zu tun.
Oft existiert ein ViewModel das in vielen Bereichen der App verwendet und hin und wieder geändert wird.

Diesen State zu ändern kann ein Performanceproblem mit sich bringen, gerade wenn die App Cardlayouts oder Tabs verwendet und somit ein Großteil der App zu jeder Zeit gerendert werden muss.

Technisch

Um genau diesem Problem entgegenzuwirken, haben wir eine simple Simulation entwickelt. Der Button Switch test and vm content (simple) wechselt auf einen zufälligen Tab und ändert den Inhalt des ViewModels, das in jedem Tab verwendet wird, auf einen zufälligen Wert.

 

// Button Handler:
let tabpanel = this.up('tabpanel');
let vm = tabpanel.getViewModel();
tabpanel.setActiveItem(Math.floor(Math.random() * tabpanel.items.length));
vm.set('binding', Math.random());

 

Google Chromes Performanceanalyse macht sofort einige interessante Phänomene sichtbar.

Die Grafik zeigt zwei ähnlich große Blöcke, die beide durch den Buttonhandler ausgelöst wurden. Der linke Bereich Event (click) führt aktiv einen neuen Tab ein und ändert den Inhalt des ViewModels.

Der rechte Bereich übernimmt den neuen Inhalt des ViewModels in die Views. Eine im allgemeinen gute Optimierung für die Auswertung von ViewModels wird uns hier zum Verhängnis. Änderungen am ViewModel wirken sich nicht sofort auf die Views aus, sondern werden erst nach kurzer Zeit in einem festgelegten Intervall ausgewertet und gerendert. Das hat den Vorteil, dass mehrere zusammenhängende Änderungen am ViewModel, beispielsweise durch einen Buttonhandler ausgelöst, nicht zu genauso vielen Renderings führen. Erst wenn die Änderung des ViewModels vollständig abgeschlossen ist, werden alle Änderungen geschrieben.

Alle Änderungen an der View werden in einem großen Block berechnet und gerendert. Der Browser muss hier keine Inhalte doppelt berechnen.

Sobald große Änderungen an den Views nötig sind würde es aber mehr Sinn machen die ViewModel Änderungen gleich mit auszuwerten. Verwendet man den zweiten Button Switch test and vm content (optimized) wird folgender Code ausgeführt:

 

Ext.suspendLayouts(); // Buffer layout operations
let tabpanel = this.up('tabpanel');
let vm = tabpanel.getViewModel();
tabpanel.setActiveItem(Math.floor(Math.random() * tabpanel.items.length));
vm.set('binding', Math.random());
vm.notify(); // Notify views of viewmodel changes
Ext.resumeLayouts(true); // Render buffered layout changes

 

besonders das vm.notify ist an dieser Stelle sehr wichtig. Ohne diese Zeile würde trotz suspendLayouts und resumeLayouts eine Änderung am ViewModel erst nach dem nächsten Timer Interval gerendert werden.

Durch diese einfache Änderung erhalten wir folgendes Bild aus der Performanceanalyse:

Ein paar Zahlen

Benchmark: (Ausgabe in der Konsole).
Jeweils 10 Stichproben ergeben auf einem Desktoprechner mit aktuellem i5 CPU und der neuesten Chrome und Firefox Version:

 

Test

 

 

Chrome [simple]

 

 

Firefox [simple]

 

 

Chrome [optimized]

 

 

Firefox [optimized]

 

 

Minimum

 

 

271.5 ms

 

 

162 ms

 

 

128.2 ms

 

 

87.2 ms

 

 

Maximum

 

 

330.7 ms

 

 

276.2 ms

 

 

139 ms

 

 

98 ms

 

 

Durchschnitt

 

 

309.5 ms

 

 

194.2 ms

 

 

133.7 ms

 

 

92.1 ms