Hallo Robert,
Für „billige“ Garbage Collection sieht man die im Normalfall aber ziemlich prominent als bekanntes „Sägezahn“-Muster im Speicherbedarf als Funktion der Zeit.
Meine Meinung: Für normale Web‑ oder App‑Logik ist Struktur, Lesbarkeit und mentale Effizienz deutlich wertvoller als Mikro‑Optimierung.
Inline‑Funktionen in Schleifen sind heute praktisch, ich betone praktisch, kein Performanceproblem. JS‑Engines optimieren Funktionsobjekte von Hause aus aggressiv. Moderne Engines wie V8, SpiderMonkey, JavaScriptCore, erzeugen Funktionsobjekte extrem effizient. Sie erkennen Muster; sie inlinen Funktionen; und sie recyceln Speicher sehr schnell. Der GC räumt solche kurzlebigen Objekte im "nursery space" (bekanntlich der ultraschnelle Bereich für temporäre Werte) auf.
Das bedeutet: Ja, es entsteht pro Iteration ein neues Funktionsobjekt – aber das kostet fast nichts. Der Unterschied ist messbar nur in extremen Szenarien (Millionen Iterationen in tight loops).
Ich kann doch nicht anderen Entwicklern pauschal unterstellen, dass sie nicht in der Lage wären, ihre Architektur beurteilen zu können, und dann Optimierungs-Dogmen aufstellen, die sich in der Praxis als unnötig herausstellen.
Klar:
wenn die Funktion groß ist und in mehreren Schleifen wiederverwendet wird
oder die Schleife millionenfach pro Sekunde läuft (z. B. in einem Game‑Loop)
oder die Funktion stabil optimiert werden muss (z. B. JIT‑Hot‑Path),
dann kann ich natürlich nicht lokal deklarieren. Aber für normale Web‑Apps ist Mikro-Optimierung irrelevant. Die Tatsache, dass die Funktion pro Iteration neu erzeugt wird, ist kein JIT‑Problem – das betrifft nur den GC, und der GC-Aufwand ist praktisch minimal.
Wenn man sich daran gewöhnt, lokale Inline‑Funktionen zu verwenden – auch in Schleifen –, dann besteht tatsächlich die Gefahr, dass man irgendwann Logik und Seiteneffekte vermischt, z. B. indem man in einer Schleifen‑lokalen Funktion plötzlich DOM‑Manipulationen unterbringt.
Aber:
Das ist kein Problem der Technik, sondern ein Problem der Disziplin und Architektur. Und es lässt sich sehr klar abgrenzen hier:
Ich verwende Schleifen-Inline‑Funktionen für reine Logik, also Berechnungen, Filter, Mappings, kleine Hilfsoperationen. Aber natürlich keine DOM‑Manipulationen, Netzwerkaufrufe oder State‑Mutationen außerhalb des lokalen Kontexts.
Solche Seiteneffekte (DOM‑Mutationen, Netzwerk‑I/O, globaler State) werden in dedizierten, benannten Funktionen außerhalb des Loop‑Scopes gekapselt: in klar benannte, höher liegende Scopes, – nicht global – , aber eine Ebene höher als die Schleife. Letzteres ist eine einfache mentale Leitplanke.
Und ich habe mir angewöhnt, Inline‑Funktionen klein zu halten. Wenn eine Inline‑Funktion zu groß wird, ist das für mich ein Signal: "Diese Funktion verdient eine eigene Ebene."
Bei mir dürfen Schleifen-Inline‑Funktionen rechnen, aber nichts anfassen. Alles, was blinkt, klickt oder DOM schreit, kommt in eine eigene Funktion außerhalb des Schleifen-Scopes.
Und zusätzlich:
Ich pers. arbeite sehr viel mit Folding (bei persistentem Folding-State im Editor). Das bedeutet: Große Funktionen klappe ich zu -> ich sehe sofort, wenn etwas zu groß wird. Gefoldete Inline‑Funktionen bleiben sichtbar -> ich erkenne schnell, wenn dort "zu viel passiert" oder "das Falsche passiert".
Der Vorteil der Kombination von Folding und Inline-Funktionen kommt überhaupt erst zum Tragen, wenn beide Techniken gleichzeitig angewendet werden. Sie ergänzen sich gegenseitig in einer Weise, die mich selbst überrascht hat! Geradezu perfekt in diesem Sinne! Imho sehr zu empfehlen.
Ich denke, wir werden uns wohl einig sein, dass globaler Namespace als riskant und fehleranfällig gilt. Ich hab diesbezüglich die klassische Kritik am "globalen Müllhaufen" in Erinnerung.
Du möchtest jetzt eine dogmatische Grenze ziehen und Inline-Funktionen aus Iterationen pauschal heraushalten. Kann man so machen, warum nicht.
Ich pers. wäre da etwas liberaler und würde keinem Entwickler voreingenommen eine Unfähigkeit unterstellen, dass er seine eigene Architektur nicht beurteilen könnte. Aber genau das tust Du, wenn Du meine Entscheidung für eine Schleifen-Inline-Funktion als "Schlurigkeit/Nachlässigkeit/Ignoranz" etikettierst.
Wenn ich eine Flasche Milch kaufen möchte, brauch ich keinen LKW. Und wenn ich umziehen will, dann ist ein VW Polo eher ungünstig. Die Entscheidung, ob LKW oder Polo, würde ich flexibel dem jew. Coder überlassen, anstatt belehrend Dogmen aufzustellen und danach den als Dogma-Ignoranten Etikettierten zu unterstellen, sie wären nachlässig und schludrig in der Nicht-Beachtung des Dogmas.
„kaum macht man's richtig, geht's.“
Ja, das ist typisch für Dogmatiker, dass sie ihr eigenes Dogma als "richtig" betrachten und dann noch einen draufsetzen, indem sie behaupten, bei ihnen "geht's", wie als ob es "immer" ginge:
Also ich ziehe meinen Hut vor Dir, wenn Du zu denjenigen gehörst, die nicht mind. 50% ihrer Zeit mit Fehlersuche und Debugging verbringen. Aber weil ich solch eine Person noch nie, nie kennengelernt habe, unterstelle und spekuliere ich jetzt mal, dass es bei Dir nicht anders sein wird.
Und nun frage ich Dich: Hast Du Dich nicht schon mal gefragt, warum das so ist? Also warum Coden überwiegend Fehlersuche und Debugging bedeutet?
Und warst Du selbst nicht oft genug frustriert und müde, weil Du stundenlang in Deinem eigenen Code irgendeinen Patzer identifizieren musstest?
Hier können, um beim Thema zu bleiben, lokal gehaltene Inline-Funktionen, auch innerhalb von Schleifen, sehr wohl hilfreich sein, weil ich "in dieser Ecke" aufgrund der Lokalität nicht wühlen muss.
Soweit mein Plädoyer für "Local Reasoning". Jetzt hab ich aber 2 Tage zu tun: Gestern ist die neue LTS Kubuntu zum Download freigegeben worden. Und die kommt jetzt auf meine Kiste. Ich könnte, wenn ich wollte, in 1 Stunde fertig sein. Aber ich will nicht alle meine Konfigs pauschal übernehmen, sondern mir das neue Teil sukzessive genauer ansehen :-)
Gruß, fischlak
--
Eitelkeit und Intelligenz sind Gegensätze. Nur Mist, dass ich so eitel bin...