So implementieren Sie eine Array-Lazy-Evaluation-Bibliothek in JavaScript

So implementieren Sie eine Array-Lazy-Evaluation-Bibliothek in JavaScript

Überblick

In der Programmiersprachentheorie ist Lazy Evaluation (englisch: Lazy Evaluation), auch übersetzt als Lazy Calculation, Lazy Evaluation, auch Call-by-Need genannt, ein Konzept der Computerprogrammierung. Sein Zweck besteht darin, den Arbeitsaufwand des Computers zu minimieren. Es hat zwei verwandte, aber unterschiedliche Bedeutungen, die als „verzögerte Auswertung“ und „minimierte Auswertung“ ausgedrückt werden können. Neben Leistungsverbesserungen besteht der wichtigste Vorteil der verzögerten Auswertung darin, dass ein unendlicher Datentyp erstellt werden kann.

Nachdem ich die Lazy Evaluation in funktionalen Sprachen gesehen hatte, wollte ich eine möglichst einfache Implementierung in JavaScript schreiben, um mein Verständnis der Lazy Evaluation zu vertiefen. Es werden zwei Methoden verwendet, die beide weniger als 80 Zeilen benötigen, um eine grundlegende Array-Lazy-Auswertung zu implementieren.

So erreichen Sie es

Bei der verzögerten Auswertung wird nicht bei jeder Auswertung ein Wert zurückgegeben, sondern eine Auswertungsfunktion mit Berechnungsparametern. Die Berechnung wird jedes Mal ausgeführt, wenn der Wert verwendet werden soll.

Wenn mehrere verzögerte Operationen vorhanden sind, wird eine Kette von Auswertungsfunktionen gebildet. Bei jeder Auswertung wertet jede Auswertungsfunktion die vorherige Auswertungsfunktion aus und gibt einen Wert zurück. Wenn die Berechnungsfunktion schließlich beendet wird, wird ein Beendigungswert zurückgegeben.

Konkrete Umsetzung

Bestimmen Sie die Beendigung der Bewertungsfunktion

Jede Auswertung der Funktion gibt unterschiedliche Daten zurück. Daher muss ein eindeutiger Wert als Markierung verwendet werden, um zu bestimmen, ob der Fluss abgeschlossen ist. Es kommt einfach vor, dass Symbol() ein neues Symbol erstellen kann, dessen Wert keinem anderen Wert entspricht.

const over = Symbol();

const istÜber = Funktion (_Über) {
  Rückgabewert _over === über;
}

Funktionsbereich generieren

Die Bereichsfunktion akzeptiert einen Start- und einen Endparameter, gibt eine Auswertungsfunktion zurück, führt die Auswertungsfunktion aus, um einen Wert zurückzugeben, und gibt den Endwert zurück, wenn sie beendet wird.

const range = Funktion (von, bis) {
  sei i = von;
  Rückgabefunktion () {
    wenn (i < bis) {
      ich++
      console.log('Bereich\t', i);
      Rückkehr ich
    }
    zurückkommen;
  }
}

Transformationsfunktionskarte

Akzeptiert eine Auswertungsfunktion und eine Verarbeitungsfunktion, ruft die Daten im Auswertungsfunktionsfluss ab, verarbeitet die Daten und gibt einen Fluss zurück.

const map = Funktion (Flow, Transform) {
  Rückgabefunktion () {
    const Daten = Fluss();
    console.log('map\t', Daten);
    gibt isOver(Daten) zurück? Daten: transformieren(Daten);
  }
}

Filter

Akzeptiert eine Auswertungsfunktion, filtert die Daten im Auswertungsfunktionsfluss, findet die passenden Daten und gibt sie zurück.

const filter = Funktion (Fluss, Bedingung) {
  Rückgabefunktion () {
    während(wahr) {
      const Daten = Fluss();
      wenn (isOver(data)) {
        Daten zurückgeben;
      }
      wenn(Bedingung(Daten)) {
        console.log('filter\t', Daten);
        Daten zurückgeben;
      }
    }
  }
}

Unterbrechungsfunktion stoppen

Akzeptiert eine Auswertungsfunktion und unterbricht, wenn eine bestimmte Bedingung erreicht ist. Sie können eine Abschlussfunktion plus eine Stoppfunktion verwenden und dann eine Take-Funktion implementieren.

const stop = Funktion (Fluss, Bedingung) {
  lass _stop = false;
  Rückgabefunktion () {
    wenn (_stop) zurückgeben;
    const Daten = Fluss();
    wenn (isOver(data)) {
      Daten zurückgeben;
    }
    _stop = Bedingung(Daten);
    Daten zurückgeben;
  }
}

const take = Funktion(Fluss, Num) {
  sei i = 0;
  Rückgabestopp (Flow, (Daten) => {
    gibt ++i >= num zurück;
  });
}

Sammlungsfunktion Join

Da alles, was zurückgegeben wird, eine Funktion ist, müssen wir am Ende eine Join-Funktion verwenden, um alle Werte zu sammeln und ein Array zurückzugeben.

const join = Funktion (Fluss) {
  konstantes Array = [];
  während(wahr) {
    const Daten = Fluss();
    wenn (isOver(data)) {
      brechen;
    }
    array.push(Daten);
  }
  Array zurückgeben;
}

prüfen:

const nums = join(take(filter(map(range(0, 20), n => n * 10), n => n % 3 === 0), 2));
console.log(Zahlen);

Ausgabe:

Bereich 1

Karte 1

Bereich 2

Karte 2

Bereich 3

Karte 3

Filter 30

Bereich 4

Karte 4

Bereich 5

Karte 5

Bereich 6

Karte 6

Filter 60

Eine elegantere Implementierung

Die verzögerte Auswertung wird mit den oben genannten Funktionen + Abschlüssen implementiert, ist aber immer noch nicht elegant genug. Der Großteil des Codes wird iteriert und beurteilt, ob die Auswertung abgeschlossen ist. Tatsächlich gibt es eine bessere Möglichkeit, in es6 eine verzögerte Auswertung zu erreichen, nämlich die Verwendung von Generatoren. Generatoren haben uns geholfen, Iterationen zu lösen und festzustellen, ob der Fluss abgeschlossen ist. Wir können uns auf die Logik konzentrieren und prägnanteren, leicht verständlichen und klar strukturierten Code schreiben.

const range = Funktion* (von, bis) {
  für(lass i = von; i < bis; i++) {
    console.log('Bereich\t', i);
    Ertrag i;
  }
}

const map = Funktion*(Fluss, Transformation) {
  für (const data of flow) {
    console.log('map\t', Daten);
    Ertrag(Transformation(Daten));
  }
}

const filter = funktion*(fluss, bedingung) {
  für (const data of flow) {
    console.log('filter\t', Daten);
    wenn (Bedingung(Daten)) {
      Ertragsdaten;
    }
  }
}

const stop = Funktion*(Fluss, Bedingung) {
  für (const data of flow) {
    Ertragsdaten;
    wenn (Bedingung(Daten)) {
      brechen;
    }
  }
}

const take = Funktion (Fluss, Zahl) {
  lass count = 0;
  const _filter = Funktion (Daten) {
    zählen++
    gibt Anzahl >= Zahl zurück;
  }
  Rückgabestopp (Flow, _Filter);
}

Vervollständigt wird es durch das Hinzufügen von Kettenaufrufen.

Klasse _Lazy{
  Konstruktor() {
    dieser.iterator = null;
  }

  Bereich(...args) {
    dieser.Iterator = Bereich(...args);
    gib dies zurück;
  }

  Karte(...args) {
    dieser.iterator = map(dieser.iterator, ...args);
    gib dies zurück;
  }

  filter(...args) {
    dieser.Iterator = Filter(dieser.Iterator, ...Argumente);
    gib dies zurück;
  }

  nehme(...args) {
    dieser.iterator = nehme(diesen.iterator, ...args);
    gib dies zurück;
  }

  [Symbol.iterator]() {
    gib diesen Iterator zurück;
  }

}

Funktion faul () {
  gibt neues _Lazy() zurück;
}

Zum Schluss testen Sie es noch einmal:

const nums = lazy().range(0, 100).map(n => n * 10).filter(n => n % 3 === 0).take(2);

für (sei n von Nums) {
  console.log('num:\t', n, '\n');
}

Ausgabe:

Bereich 0

Karte 0

Filter 0

Nummer: 0

Bereich 1

Karte 1

Filter 10

Bereich 2

Karte 2

Filter 20

Bereich 3

Karte 3

Filter 30

Zahl: 30

Okay, es ist erledigt.

Zusammenfassen

Auf diese Weise haben wir eine einfache Bibliothek für die verzögerte Array-Auswertung fertiggestellt. Hier implementieren wir lediglich die verzögerte Auswertung. Um sie in das Projekt einzufügen, müssen viele Details hinzugefügt werden. Da der Code nur 80 Zeilen umfasst, können Sie das Prinzip der Lazy Evaluation klar verstehen und Ihr Verständnis von Generatoren vertiefen.

Oben finden Sie Einzelheiten zur Implementierung einer Array-Lazy-Evaluation-Bibliothek mit JavaScript. Weitere Informationen zur Implementierung einer Array-Lazy-Evaluation-Bibliothek mit JavaScript finden Sie in den anderen verwandten Artikeln auf 123WORDPRESS.COM!

Das könnte Sie auch interessieren:
  • Schreiben von wartbarem, objektorientiertem JavaScript-Code
  • Verwenden von JavaScript zum Erstellen von wartbarem Diashow-Code
  • Lassen Sie uns darüber sprechen, was das URL-Objekt von JavaScript ist
  • Detaillierte Erklärung der praktischen Anwendung regulärer Ausdrücke in JavaScript
  • Detaillierte Erklärung des Befehlsmodus in der Javascript-Praxis
  • So erstellen Sie Ihren eigenen nativen JavaScript-Router
  • So lernen Sie algorithmische Komplexität mit JavaScript
  • Verwenden Sie einige Interviewfragen, um den Ausführungsmechanismus von JavaScript zu untersuchen
  • Bringen Sie Ihnen bei, wie Sie wartbaren JS-Code schreiben

<<:  MySQL-Tutorial zum Bereitstellen mehrerer Instanzen auf einer einzigen Maschine mit mysqld_multi

>>:  So erstellen Sie eine lnmp-Umgebung im Docker

Artikel empfehlen

Tipps zum Festlegen von HTML-Tabellenrändern

Für viele HTML-Neulinge ist die Tabelle <table...

Beispiel für die Implementierung von QR-Code-Scaneffekten mit CSS3

Online-Vorschau https://jsrun.pro/AafKp/ Erster B...

Detaillierte Erklärung des Rewrite-Moduls von Nginx

Das Umschreibmodul ist das Modul ngx_http_rewrite...

Vue implementiert die browserseitige Code-Scan-Funktion

Hintergrund Vor nicht allzu langer Zeit habe ich ...

So beheben Sie das Eingabe-Jitter-Problem beim WeChat-Applet

Finden Sie das Problem Schauen wir uns zunächst d...

Linux verwendet join -a1, um zwei Dateien zusammenzuführen

Um die folgenden beiden Dateien zusammenzuführen,...

So legen Sie eine horizontale Navigationsstruktur in HTML fest

In diesem Artikel werden Ihnen zwei Methoden zum ...

Lösen Sie das Problem, dass Docker Pull zurückgesetzt wird

In diesem Artikel wird beschrieben, wie Sie das P...

4 Möglichkeiten zur Optimierung von MySQL-Abfragen für Millionen von Daten

Inhaltsverzeichnis 1. Der Grund, warum das Limit ...