Gibt es eine Möglichkeit, versteckte Klassen in Javascript sauber zu verwenden, wenn Sie nicht wissen, was die Eigenschaften sein werden?

9

Ich habe ein (GIS) Projekt, das Kunden große Datenmengen (Tausende von Datensätzen) anzeigt. Wo nötig / möglich / erforderlich, verwenden wir serverseitige Paginierung / Filterung / Datenmanipulation, aber es gibt Fälle, in denen es am effizientesten ist, die Daten im JSON-Format an den Client zu senden und deren Filter zu filtern.

Da die Datenmenge groß ist, formatieren wir sie, um Bandbreite und Analysezeit zu sparen. Statt einzelner Objekte senden wir eine Struktur, die zuerst die Attributnamen und dann die Werte in einem einzelnen flachen Array enthält. Auf dem Client erstellen wir dies in traditionellere JSON-Objekte zurück, bevor eine andere Verarbeitung stattfindet. zB:

%Vor%

Der Code dafür sieht ein wenig so aus:

%Vor%

Angesichts der Tatsache, dass sich die Attribute je nach Kundendaten ändern können, gibt es eine Möglichkeit, diese Übersetzung durchzuführen, die versteckte Klassen in modernen JavaScript-Engines wie V8 nutzt? Ich habe einige Mikrobenchmarks ähnlich wie in unserem Anwendungsfall ( Ссылка ) erstellt, wobei die Arbeit mit json so funktioniert, dass versteckte Klassen verwendet werden Größe schneller als das Erstellen der Objekte wie oben. Ich kann etwas von diesem Boost mit "eval" bekommen, um Objekte zu erstellen, aber das fühlt sich hässlich an (dies wird in der js-Geige demonstriert). Gibt es einen besseren Weg? Vielleicht mit einer Variante von Object.create, oder so ähnlich?

    
tofarr 21.05.2014, 09:59
quelle

3 Antworten

1
  

Ich kann etwas von diesem Boost mit "eval" bekommen, um Objekte zu erstellen, aber das fühlt sich hässlich an.

Es gibt einen weniger hässlichen Weg mit dem Konstruktor Function . Außerdem können weitere Optimierungen vorgenommen werden, indem die Werte sofort den Eigenschaften zugewiesen werden, anstatt sie mit null zu initialisieren und dann erneut durch das attrs -Array zu iterieren, wie es das adHoc tut. Sie würden einfach jede der Zeilen, die Sie in der Antwort erhalten (Array? String? Byte - was auch immer?) Als Parameter für die Factory übergeben.

Ich habe auch die Erstellung der Funktion factory aus der Funktion create entfernt, so dass nur eine Funktion instanziiert (und nach genügend Aufrufen für sie optimiert) wird.
Eine angemessene Menge an Zeit in Ihrer Testschleife wird für getTotal ausgegeben, also habe ich das auf ähnliche Weise optimiert. Die Verwendung von getTotalAdHoc beim Testen der optimierten Lösung reduziert die gemessene Zeit drastisch (Sie können auch mit getTotalOptimum testen).

%Vor%

( aktualisierte jsfiddle )

Ich habe noch nicht versucht, die komplette Schleife in den generierten Code zu verschieben, was einige Funktionsaufrufe vermeiden könnte, aber ich denke nicht, dass dies notwendig ist.

    
Bergi 24.05.2014, 20:43
quelle
2

Sie meinen so etwas richtig?

%Vor%

Sie können unsere Geige hier überprüfen: Ссылка (Mit etwas Vergleichscode). Es sollte die gleiche "versteckte Klasse" (d. H.% Co_de%) verwenden. Nicht sicher, wie viel schneller es ist!

Aber wenn Sie wirklich wollen, dass Ihr Code nicht blockiert, warum laden Sie die Seite nicht, fordern Sie die Daten dann über AJAX an und führen Sie dann den gesamten Code aus, wenn Sie eine Antwort erhalten.

    
Matthew Wilcoxson 24.05.2014 19:37
quelle
1

Aus irgendeinem Grund habe ich mich gerade an diese Frage erinnert ... und ich habe gerade eine Lösung gefunden, die viel schmutziger ist als die Verwendung von eval , die aber einen enormen Geschwindigkeitsschub verursacht. Der Nachteil ist, dass der Code ähnlich wenig wartbar ist wie bei der Verwendung von eval .

Die Grundidee ist: Wenn Sie die Attributnamen erhalten, generieren den Funktionscode, um die folgenden Daten in JavaScript zu analysieren und fügen Sie sie in <script> dem <head> hinzu.

Ja, ist das nicht schmutzig? : -)

Wenn die Leistung für Sie so wichtig ist, wird es Ihnen definitiv helfen ... hier ist eine modifizierte Version Ihres microbenchmak, die es beweist: Ссылка

Einige Bemerkungen zum Code ...

Die beiden Funktionen createWithGeneratedFunction und getTotalWithGeneratedFunction sind lediglich Wrapper-Funktionen, die von produktivem Code verwendet werden können. Alles, was sie tun, ist sicherzustellen, dass das <script> mit den generierten Funktionen eingerichtet ist und dann aufrufen.

%Vor%

Das eigentliche Arbeitspferd ist das makeSureScriptsAreSetUp mit den Funktionen, die es erstellt. Ich werde Zeile für Zeile durchgehen:

%Vor%

Wenn das erforderliche <script> -Tag bereits eingerichtet wurde, kehrt diese Funktion direkt zurück, da nichts mehr dafür zu tun ist.

%Vor%

Dies bereitet die Erstellung der erforderlichen Funktionen vor. Die Variable theFunctions wird mit dem Code gefüllt, der in den <script> -Tag-Inhalt eingefügt wird.

%Vor%

Dies vervollständigt den Code für die Parsing-Funktion. Offensichtlich "parst" es einfach die Zahlen 0 bis numValues in diesem Mikrobenchmark. Wenn Sie jedoch value++ durch etwas wie TheObjectThatTheClientSentMe.values[value++] ersetzen, sollten Sie dem, was Sie in Ihrer Frage beschrieben haben, sehr nahe kommen. (Es wäre natürlich sehr sinnvoll, value in index umzubenennen.)

%Vor%

Damit ist der Code für die Verarbeitungsfunktion abgeschlossen. Da Sie scheinbar mehrere Verarbeitungsfunktionen benötigen, könnte dieser Code besonders hässlich zu schreiben und zu pflegen sein.

%Vor%

Am Ende setzen wir einfach den <script> -Tag-Inhalt auf den Code, den wir gerade erstellt haben. Durch das Hinzufügen dieses Tags zu <head> wird die verborgene Klassenmagie von Chrome auftreten und den Code SEHR schnell machen.

Was die Erweiterbarkeit betrifft: Wenn Sie verschiedene Attribut- / Wertsätze vom Server auf derselben Seite abfragen müssen, sollten Sie jedem Parser / Verarbeitungsmethode eindeutige Namen geben. Wenn Sie zum Beispiel attrs = ["foo","bar"] und next attrs = ["foo","bar","baz"] zum ersten Mal erhalten, können Sie das mit dem Unterstrich verknüpfte Attributnamen-Array mit den generierten Funktionsnamen verknüpfen.

Anstatt beispielsweise createWithGeneratedFunctionAdded zu verwenden, könnten Sie createWithGeneratedFunctionAdded_foo_bar für das erste Attribut / Wertsatz und createWithGeneratedFunctionAdded_foo_bar_baz für das zweite Attribut / Wertsatz verwenden. Ein attr -Parameter könnte dann zu den Wrapper-Funktionen hinzugefügt werden, die verwendet werden, um die richtige Codezeile für ein eval zu generieren (ja, hier würde das böse eval zurückkehren), um die korrekte generierte Funktion auszulösen. Offensichtlich wäre der Parameter attr auch für die Funktion makeSureScriptsAreSetUp erforderlich.

    
Hauke P. 01.09.2014 12:32
quelle