2013-03-26 9 views
24

Ich habe eine AngularJS-App mit einem ausgelagerten Gitter (zwei verschachtelte ng-Wiederholung). Eine Seite hat ungefähr 25x40 Eingabeelemente. Am Anfang, der 1000 Bindungen machte, war die Paging-Leistung akzeptabel.Wie beschleunigt man eine AngularJS-Anwendung?

Aber dann wächst die Komplexität der Seite: dynamische Klassen, variierende Kontextmenüs, bedingter Inhalt für jede Zelle des Gitters. Und mit geschätzten 6000 Bindungen (6 pro Eingabeelement) wurde das Paging unbrauchbar langsam.

Meine Frage ist: Wie gehe ich generell Leistungsprobleme in AngularJS an? Der offensichtliche erste Schritt ist zu messen. Aber die Ergebnisse des Chrome Profilers sagen mir nicht viel, weit davon entfernt zu wissen, wie es weitergeht.

Self  Total       Function 
----------------------------------------------------------------- 
24 ms 2.79 s angular.js:7997   Scope.$digest 
1 ms  1 ms controllers.js:365  setViewportData 
16 ms  692 ms angular.js:13968  ngRepeatWatch 
8 ms  22 ms angular.js:6439   extend.literal 
9 ms 1.22 s angular.js:14268  ngSwitchWatchAction 
16 ms  45 ms angular.js:12436  ngModelWatch 
0  621 ms angular-ui-4.0.js:264 initDateWidget 
0   13 ms angular.js:12859  ngClassWatchAction 
0   70 ms angular.js:14184  ngStyleWatchAction 
1 ms  5 ms angular-ui-4.0.js:261 getOptions 
0   16 ms angular.js:579   copy 
0   1 ms angular.js:4558   interpolateFnWatchAction 
1 ms  2 ms angular.js:5981   token.fn.extend.assign 
0   37 ms angular.js:8151   Scope.$eval 
1 ms  1 ms angular.js:6137   extend.constant 
14 ms  16 ms angular.js:651   equals 
1 ms  1 ms angular.js:4939   $interpolate.fn 

Abgesehen: Gibt es eine Chance, dass ‚Object.observe()‘ wird die Dinge in Zukunft beschleunigen (ohne Berücksichtigung von ‚initDateWidget‘, das ist natürlich ein anderes Thema)?

+0

ich hier in dieser Frage gearbeitet Menschen Anwendungen beschleunigen NG2 zu helfen, sollte es in der Lage sein, Ihnen einige Einblicke zu bieten: https: // Stackoverflow. com/questions/42583421/how-to-compress-and-optimieren-ein-angular2-Anwendung – HappyCoder

Antwort

27

Die Sache, die Sie tun können, wird Ihre Angular App am meisten beschleunigen, ist es, diese Bindungen zu reduzieren, wo Sie können. Eine Möglichkeit wäre, eine Direktive zu erstellen, die die Tabelle für Sie mit DOM-Manipulation ausbaut, anstatt ng-repeats zu verwenden. Dies wird die Anzahl der zu überwachenden Uhren insgesamt reduzieren und den $ Digest sehr viel schneller machen.

Ich weiß, dass es hässlich ist, das zu tun, aber Angular ist nicht wirklich dazu gedacht, mehr als 3000 Bindungen zu erstellen. Da es ein Digest macht und es kein Beobachtermuster ist, verlangsamt es wirklich die Dinge, die viele eingerichtet haben.

Sie könnten sogar einen hybriden Ansatz verwenden, bei dem Sie immer noch die ng-Wiederholung verwenden, aber alle Werte wurden im DOM mit direkter DOM-Manipulation aus einer benutzerdefinierten Anweisung platziert, wodurch alle Bindungen vermieden werden.

20

Wenn Sie dies noch nicht getan haben, installieren Sie bitte das AngularJS Chrome-Plugin, Batarang, mit dessen Hilfe Sie herausfinden können, welche Ihrer Bindungen Ihnen Kummer bereitet. Wie die andere Antwort nahelegt, ist das, was Sie suchen, wahrscheinlich ein kleiner Fall einer Unendlich-Scroll-Einrichtung für Ihre Tabelle, wobei das Modell, an das Sie binden, die Untermenge ist, die Sie auf dem Bildschirm anzeigen.

Die ng-Grid-Komponente implementiert dies und es könnte sich lohnen, sie entweder direkt zu verwenden oder die Technik zu stehlen. http://angular-ui.github.com/ng-grid/

+0

Was für ein tolles Werkzeug! Danke, danke, danke! Dies sollte auf jedem Entwickler-Computer installiert werden ;-) – Sebastian

+0

Nettes Tool, aber es zeigt mir immer noch, dass ngModelWatch 91.9% der Gesamtzeit benötigt, also ist es wirklich schwer herauszufinden, vielleicht benutze ich es falsch – Highmastdon

13

Ein bisschen spät, aber vielleicht klappt dies für Sie:

https://github.com/Pasvaz/bindonce

Sie es auf diejenigen verwenden können, Bindung, die nicht so $ ändern sollen verdauen sie nicht mehr verarbeiten.

18

Ressourcen

This post about angularJS performance on large lists hat einen schönen Überblick über die Optionen, die Sie für Performance-Tuning haben.

Die obigen Antworten (mit Ausnahme des Batarang-Plugins) werden ebenfalls erwähnt. Dies ist nur eine Übersicht über die Tipps in diesem Artikel.

reduzieren Daten mit LimitTo (Paginierung)

Einer der offensichtlichen Lösungen ist die Menge der Bindungen durch die Reduzierung der Anzahl der Elemente in der Ansicht zu reduzieren.Die Paginierung der Daten kann mit dem Filter limitTo unter ng-repeat erfolgen.

Beispiel bei How to improve performance of ngRepeat over a huge dataset (angular.js)? Dieser Artikel hat auch a jsbin example verknüpft.

Achten Sie auch darauf, keine Inline-Methode für die Datenbereitstellung zu verwenden, da dies bei jedem $ Digest ausgewertet wird.

<li ng-repeat="item in filteredItems()"> // Bad idea, since very often evaluated. 
<li ng-repeat="item in items"> // Way to go! 

entfernen Bindungen mit bindonce

Eine weitere offensichtliche Lösung ist Bindungen auf bestimmte Elemente zu entfernen. Sicher bedeutet dies, dass Updates nicht mehr in der Ansicht angezeigt werden.

Die bindonce Lösung tut viel mehr als nur das Entfernen der 2-Wege-Bindung. Im Grunde wartet es darauf, dass der Wert einmal gebunden wird, bevor die Bindung entfernt wird. Am besten lesen Sie selbst. Überprüfen Sie the bindonce project für Details.

In dem oben aufgeführten Artikel gibt es auch Informationen über ein Muster, das mit 2 Listen arbeitet. Eine für die Visualisierung und eine als Datenquelle.

Verwenden ng-grid

Ng-grid hat den Vorteil, dass sie nur die Elemente machen die derzeit sichtbar sind. Lesen Sie mehr unter .

Ähnlich ng-if entfernt die versteckten Elemente vollständig aus dem DOM-Baum, während ng-show nur hält sie an Ort und Stelle aber versteckt. Berücksichtigen Sie, dass ng-if eine Kopie des Originals (Original ist der Schlüssel, nicht die Änderungen, das ist) Element an Stelle, wenn es erneut angezeigt wird.

Tipps zum Filtern

Der Artikel auch zum Filtern von Listen einige gute Tipps hat.

Wie mit ng-show die gefilterten Elemente ausblenden, da auf diese Weise keine Unterliste der Daten erstellt werden muss.

Und eine andere Technik, die als "entprellen Benutzereingabe" bezeichnet wird. Die letzte Option besteht darin, mit der Filterung zu warten, bis der Benutzer die Eingabe beendet hat. Einschließlich a jsfiddle example.

Mehr

Weitere Tipps finden Sie in der verknüpften Artikel. Dort sind auch Ressourcen aufgeführt, so dass dies ein guter Ausgangspunkt sein sollte. Die offensichtlichsten Onces und Quick Wins sind hier aufgelistet, glaube ich.

Eine weitere nette Zuschreibung ist How does data binding work in AngularJS?

6

In Winkel 1.3 und mehr können Sie einmal binden, indem Sie :: keine Notwendigkeit, andere 3-Party verwenden js

<li ng-repeat="item in :: items"> 

Das ist gut, wenn die Einzelteile nicht ändern so können Sie sie einmal binden

1

Ich habe Leistungsprobleme auftreten, wenn die Menge der Zuhörer 1000+ in einer Datenraster-Komponente exceded.

Ich löste dieses Problem, indem ich eine Direktive verwendete, die meine Ansicht mit react.js erstellt. Die Richtlinie enthüllte eine Update-Funktion.

Jedes Mal, wenn sich die Daten änderten (im Controller), löste die Aktualisierungsfunktion die Anweisung aus, und dann hat die Engine react.js das Rendering effizient durchgeführt.

Ich weiß, es ist ein großer Overhead, ein zweites Hauptrahmenwerk innerhalb eines eckigen Projekts zu verwenden, und das ist keine echte Datenbindungszauberei. aber es funktioniert viel schneller.

schließlich hörte ich auf, angular.js zu verwenden und wechselte zu react.js + FLUX. Ich denke, es ist besser, aber ich weiß, es ist nicht einfach, aus eckigen zu verschieben, aber es lohnt sich.

Angular directive that uses react.js

0

ich mit ng-Raster mit großen Daten Performance-Probleme hatte, wurde es durch das Ersetzen es mit Angular Grid gelöst. Die Demo auf der Website zeigt, dass 100.000 Zeilen problemlos verwaltet werden können.

0

Ich habe damit für ein paar Wochen gerungen. Ich habe zwei Dinge gefunden, die einen wesentlichen Unterschied gemacht haben:

(i) EINZIGE BINDUNGEN: Verwenden Sie einmalige Bindungen, wo Sie können; und (ii) DEBOUNCE: Für Eingabe, die nicht sofort weitergegeben werden muss, sondern 250ms warten kann, legen Sie eine Debounce-Einstellung fest. Dies hat einen unglaublichen Unterschied zu meiner großen ng-Wiederholungstabelle gemacht. Ich kann nicht betonen, wie effektiv eine Debounce-Einstellung war. (siehe hier: https://docs.angularjs.org/api/ng/directive/ngModelOptions)

0

bject.observe() ist ein vorgeschlagener Mechanismus, um echte Datenbindung an den Browser zu bringen. Es stellt einen Mechanismus zum Beobachten von Änderungen an Objekten und Arrays bereit und benachrichtigt andere über Mutationen, die an diesen Objekten vorgenommen werden.

<!DOCTYPE html> 
<html> 
<head> 
<base target="_blank"> 
<title>Object.observe()</title> 

<link rel="stylesheet" href="../css/main.css" /> 

</head> 

<body> 

<div id="container"> 

    <h1><a href="https://shailendrapathakbits.wordpress.com/" title="code_lab_by_shail ">code_lab_by_shail</a> Object.observe()</h1> 

    <p>An object <code>o</code> is created and <code>Object.observe()</code> is called on it.</p> 

    <p>Three changes are made to <code>o</code> and <code>Object.observe()</code> records these changes as shown below.</p> 

    <p>Use the console to find out what happens if you make further changes to <code>o</code>: it's defined in global scope.</p> 

    <p>Call <code>Object.unobserve(o, observer)</code> to stop observing changes.</p> 

    <p id="data" style="font-size: 14px;"></p> 

    <script src="js/main.js"></script> 

    <a href="https://github.com/shailendra9/objectobserver/blob/master/index.html" title="View source for this page on GitHub" id="viewSource">View source on GitHub</a> 

</div> 

<script src="../js/lib/ga.js"></script> 

</body> 
</html>