Wir bei hedersoft haben lange mit angular gearbeitet und unsere Web- und mobilen Applikationen mit diesem Framework entwickelt. Zuletzt sind wir aber auf erhebliche Performance Probleme gestoßen im Zuge der Entwicklung des User-Cockpits im hs.Crawler.

crawler_cockpit

Das User-Cockpit ist ein Frontent zur Bearbeitung von Aufgaben im Scrum Stil. Bei einer geringen Anzahl an zu verwaltenden Aufgaben war alles in Ordnung und performant. Je größer jedoch die Aufgabenanzahl wurde, desto weniger konnte mit der Anwendung gearbeitet werden. Auch alle Tipps&Tricks im Bezug auf die Performance von angular führten zu keiner Verbesserung. Es war schlicht zu langsam für eine flüssige User Experience. Wartezeiten von 18 Sekunden bei rund 400 Aufgaben sind nicht akzeptabel.

Da angular 2 noch nicht verfügbar ist, für welches eine Überarbeitung und damit einhergehend eine erhebliche Performanceverbesserung angekündigt ist, musste eine Alternative her. Nach der Sondierung aller Verfügbaren Frameworks, die ähnliches leisten wie angular, haben wir uns für React entschieden. React wurde und wird von Facebook entwickelt und erfreut sich immer größerer Beliebtheit, wenn man nach der Anzahl an Blogeinträgen und Stackoverflow Fragen geht.

React hat einen ähnlichen Funktionsumfang wie angular, unterscheidet sich aber auch in einigen Teilen deutlich. So ist das Templating vollständig über Javascript zu implementieren und nicht wie in angular über HTML Codebausteine.

Der Umbau von angular auf React hat die Anzeige von rund 400 Aufgaben von 18 auf 3 Sekunden gesenkt. Das ist schon einmal ein ganz schöner Schub. Das Problem ist, dass jede Modifikation der Liste wieder dazu führt, dass das System 3 Sekunden rechnet. Dies liegt daran, dass React bei jeder Änderung die render() Funktion für jede einzelne Aufgabe (Komponente) erneut aufruft, ob diese geändert wurde oder nicht. Die render() Funktion ist mit die kostenintensivste Funktion in React.

Außerdem werden nachgelagert weitere Funktionen aufgerufen wie bspw. componentWillUpdate() oder componentDidUpdate(). Wenn wir also genau wissen, dass an einer Komponente nichts geändert wurde, dann möchten wir verhindern, dass die kostenintensiven Funktionen unnötig ausgeführt werden. Für diesen Fall hält React glücklicherweise eine Lösung bereit: shouldComponentUpdate()!

In dieser Funktion können wir Code hinterlegen, welcher dazu führt, dass der nachgelagerte Code nicht mehr ausgeführt wird. Hier ein Beispiel:

Damit haben wir schon einmal das nachträgliche modifizieren einer einmal geladenen Liste optimiert. Anstatt jedesmal 3 Sekunden auf Änderungen zu warten, bewegt sich dies im Bereich von Millisekunden. Im nächsten Schritt werden wir nun die User Experience beim Initialen Aufbau einer großen Liste durch Lazy Loading optimieren. Dabei werden nur Komponenten gerendered, die im Sichtbaren Bereich des Browserfensters liegen. Dafür gibt es im WWW einige Beispiele, aber dazu mehr demnächst …