Lambda-Funktionen vs binden, Speicher!!! (und Leistung)

Ich würde gerne bestimmen, welche ist die beste Praxis zwischen gleichwertigen Lösungen. Der use-case ist eine Instanz einer Klasse, die hören ein Ereignis. Dr. Axel Rauschmayer lieber die lambda für die Lesbarkeit. Ich bin mit ihm einverstanden. Aber in den Begriff von performance-und memory-Verbrauch, was ist die beste?

Mit einer lambda-Funktion

class Abc {
  constructor() {
    let el = document.getElementById("my-btn")
    if (el)
      el.addEventListener("click", evt => this.onClick(evt))
  }
  onClick(evt) {
    console.log("Clicked!", evt.target)
  }
}

Kann das jemand bestätigen oder gebrechlichen wenn die lokalen Variablen (hier el) nicht beseitigt werden können, indem der garbage collector? Oder, sind moderne Browser in der Lage zu erkennen Sie nicht verwendet werden, die in der Schließung?

Mit Funktion.der Prototyp.bind:

class Abc {
  constructor() {
    let el = document.getElementById("my-btn")
    if (el)
      el.addEventListener("click", this.onClick.bind(this))
  }
  onClick(evt) {
    console.log("Clicked!", evt.target)
  }
}

Gibt es kein Speicher-Problem, aber alle benchmarks suggerieren, dass bind ist viel langsamer als ein Verschluss (ein Beispiel hier).

EDIT: ich bin nicht einverstanden mit den Kommentaren, die ignorieren das performance-Problem von bind. Ich schlage vor, zu Lesen diese Antwort mit dem code der Implementierung in Chrome. Es kann nicht effizient sein. Und ich bestehe darauf: alle die benchmarks, die ich gesehen habe, zeigen ähnliche Ergebnisse auf alle Browser.

Ist es ein Weg, um eine low-memory-Nutzung und eine gute Leistung bei der gleichen Zeit?

  • Syntax, nicht die Leistung. Implementierungen tun. Also die Antwort kann nur "es hängt". Mit der Schließung Beispiel in der jsPerf sein, der viel schneller in Ihren tests (in Firefox sowieso), wäre ich geneigt zu vermuten, dass es sich um eine Optimierung treten, dass die Beseitigung der Anruf insgesamt, die möglicherweise nicht verfügbar in der realen Welt code.
  • Ich schlage vor, event delegation Reduzierung der Anzahl von Bindungen mit der Logik zu handeln, auf der Veranstaltung eine Methode in das Objekt. Ich verstehe das nicht mit der OP gefragt, aber erwähne es als einen Punkt überlegung Wert.
  • Und nur zur info, da Ihr Beispiel, Sie könnten tatsächlich tun el.addEventListener("click", this), und dann geben Sie Ihrer Klasse einen handleEvent Methode. Wenn das Ereignis Auftritt, wird handleEvent aufgerufen wird. jsfiddle.net/8qkfxshj
  • Sind diese tatsächlich funktional gleichwertig? In der gebundenen version, die Instanz von Abc kann erreicht werden innerhalb der event-handler durch 'dieses', das Sie nicht in der lambda-version. So würde ich binden, wenn ich zu erreichen, müssen Sie die Instanz. Wenn nur die Veranstaltung.Ziel (aka das element my-btn ) erforderlich ist, würde ich in der Regel bevorzugen die lambda.
  • Seine Beispiele sind äquivalent. Ein Pfeil Funktion nicht über seine eigenen this Wert, so benutzt es die der eine er schließt vorbei.
  • Danke, ich hatte das Gefühl es war etwas, was ich bin fehlt. So viel ES6 zu lernen.
  • Danke für den trick handleEvent. Vielleicht ist es die beste Antwort: die API sollte einen Weg, um pass Kontext-Objekt this. Aber die Frage bleibt, zum Beispiel mit Versprechungen oder andere.
  • Du bist herzlich willkommen. Leider, ganz ehrlich, ich glaube nicht, dass es eine einfache Antwort auf diese Frage. Wann und wie kann eine Umsetzung der Optimierung einer bestimmten bit-code kann variieren, abhängig von der tatsächlichen situation. Ich habe gesehen, einige perf-tests, dass .bind() Funktionen in die Führung (auch in Firefox). Und das könnte sich ändern mit der nächsten Version. Sie wirklich brauchen, um herauszufinden, welche Teile der app sind die meisten performance-kritisch ist, und dann die Feinabstimmung die spezifischen Bereiche, die durch die Durchführung von tests, dass die Verwendung der realen Welt code.
  • Ich bearbeitet, um hinzufügen einen link auf das performance-Problem von bind.
  • "...mit dem code der Implementierung in Chrome. Es kann nicht effizient sein." Wie funktioniert ein user-posting ein Stück code, die von einem bestimmten release einer spezifischen Anwendung zu übersetzen, um .bind() nicht in der Lage, effizient zu sein?
  • Da der Algorithmus, beschrieben in der Spezifikation nur oben.
  • Das ist ein häufiger Fehler, den Leute machen, wenn Sie Lesen, ein spec. Die Skillung nicht geregelt, wie der code geschrieben werden muss. Es beschreibt nur die Art und Weise, in der der code sich Verhalten müssen. In anderen Worten, solange der code wirkt, als ob es geschrieben wurde, mit diesem Algorithmus, dann ist es erfüllt die Anforderungen. Wer weiß, wie viele von diesen Schritten kann ganz übersprungen, da ein optimierender compiler ermittelt, dass in bestimmten Situationen sind Sie nicht zu erreichen ist.
  • ECMAScript 6, Abschnitt 5.2 "wird Die Spezifikation oft mit einer nummerierten Liste geben Sie die Schritte in einem Algorithmus. Diese algorithmen werden verwendet, um die genaue Angabe der gewünschten Semantik des ECMAScript-Sprache konstruiert. Die algorithmen sind nicht dazu bestimmt zu bedeuten, das verwenden einer bestimmten Implementierung der Technik. In der Praxis kann effizienter algorithmen zur Durchführung einer bestimmten Funktion."
  • OK, OK, du hast Recht, die Skillung, die umgesetzt werden könnten in einem besseren Weg. Es ist bis heute nicht der Fall, wie können wir testen, auf jsperf. Aber das Speicher-Problem der lambda-Funktion gelöst werden konnten, zu. Ich würde wirklich gerne wissen, ob die aktuellen Browser haben, lösen Sie die Speicher-Problem mit der lambda-Funktion oder nicht.
  • Zusätzlich, Benjamin Links ein Kommentar unter seiner Antwort zu, dass auch eine gute Wirkung.
  • Wie ich oben erwähnt, scheint es wahrscheinlich, dass die Schließung Beispiel war komplett wegoptimiert. Nichts für ungut, aber es sollten keine Schlussfolgerungen aus einem so einfachen test. Nochmal, ich habe gesehen, perf-tests, dass .bind() in Führung. Und was Speicher-Problem haben Sie eigentlich schon erlebt?
  • Wenn es nur um die Bestätigung, dass es kein Problem, betrachten Sie es in der Regel bestätigt. Moderne GC-Implementierungen behandeln, die in Ihrem Schlaf.
  • Haben Sie einen link, um zu erklären, dass (moderne GC-Implementierung)? Ich bin wirklich interessiert. Bitte Schreibe eine Antwort mit dem Vorschlag, die API zu verwenden, wenn eine Möglichkeit vorgesehen wird, übergeben Sie die this Kontext, und vergessen Sie nicht zu erwähnen, dass die moderne GC-Implementierung kann erkennen und entfernen von ungenutzten Variablen, die sichtbar von der Schließung. Ich werde überprüfen Sie Ihre Antwort.
  • Es scheint, die Antwort auf meine Frage ist so etwas wie: Alle Optionen sind OK für den Speicher-Verbrauch (aber die lambda braucht mehr Arbeit von der GC). Und alle Optionen sollte OK sein für die Leistung in der Zukunft (auch wenn bind langsam mit aktuellen Implementierungen).
  • Ich kann es nicht beweisen, die Abwesenheit von etwas. Ich kann dir nur sagen, dass die Menschen lange gekämpft, mit memory leaks, die kam von zirkulären Referenzen, einschließlich diejenigen, die von Schließungen, vor allem bei älteren Versionen des IE. Diese Lecks wurden gezeigt, von verschiedenen Menschen zu verschiedenen Zeiten nicht mehr existieren. Ich habe einige Tests selbst, wo ich generiert Tausende von Elementen, von denen jedes die direkten Bezüge zueinander, sowie der Schließung Verweise, nur um zu sehen, wenn die GC sauber wären Sie alle auf. Sie behandelt es nur gut, aber es dauerte einige Sekunden, um dorthin zu gelangen. Das war vor ein paar Jahren.
  • Keines von diesem bedeutet, es gibt kein Leck irgendwo versteckt, die noch nicht entdeckt worden. Aber Mach dir keine sorgen über Sie, bis Sie es finden. Zukünftige Implementierungen können Regressionen. Mach dir keine sorgen, dass entweder. Es wäre unmöglich, Sie zu vermeiden.

InformationsquelleAutor Paleo | 2017-02-08
Schreibe einen Kommentar