Detaillierte Erklärung des JavaScript-Fortschrittsmanagements

Detaillierte Erklärung des JavaScript-Fortschrittsmanagements

Vorwort

Beim Schreiben von Programmen müssen wir häufig den Fortschritt anzeigen, z. B. den Ladefortschritt, den Uploadfortschritt usw.
Die gängigste Implementierungsmethode besteht darin, die abgeschlossene Menge (loadedCount) und die Gesamtmenge (totalCount) aufzuzeichnen und dann den Fortschritt zu berechnen.
Diese Methode ist einfach und grob, leicht zu implementieren, aber schwierig zu erweitern, und es muss ein Ort vorhanden sein, an dem alle loadedCount- und totalCount-Werte verwaltet werden können.
Dieser Artikel implementiert eine leichter skalierbare Methode zur Fortschrittsverwaltung basierend auf der obigen Implementierungsmethode.

Frage

Ich schreibe eine WebGL-Anwendung und muss den Ladefortschritt während der Vorladephase der Anwendung berechnen.
Der geladene Inhalt umfasst: Modellressourcen, Kartenressourcen, Skriptressourcen usw.
Die Modellressourcen enthalten Materialressourcen und die Materialressourcen enthalten Texturressourcen.
Wenn wir zur Darstellung ein Bild zeichnen, sieht die Struktur wie folgt aus:

+-------------------------------------------------------------+
| |
| Ressourcen |
| |
| +----------+ +-----------------+ +-----------------+ |
| | Skript1 | | Modell1 | | Modell2 | |
| +----------+ | | | | |
| | -------------+ | | -------------+ | |
| +----------+ | |model1.json | | | |model2.json | | |
| | Skript2 | | +------------+ | | +------------+ | |
| +----------+ | | | | |
| | +------------+ | | +------------+ | |
| +----------+ | | Material1 | | | | Material1 | | |
| | Textur1 | | | +--------+ | | | | +--------+ | | |
| +----------+ | | |Textur1| | | | | |Textur1| | | |
| | | +--------+ | | | | +--------+ | | |
| +----------+ | | +--------+ | | | | +--------+ | | |
| | Textur2 | | | |Textur2| | | | | |Textur2| | | |
| +----------+ | | +--------+ | | | | +--------+ | | |
| | +------------+ | | +------------+ | |
| | | | | |
| | +------------+ | | +------------+ | |
| | | Material2 | | | | Material2 | | |
| | +------------+ | | +------------+ | |
| +-----------------+ +-----------------+ |
| |
+-------------------------------------------------------------+

Hierbei gilt eine Prämisse: Beim Laden einer Ressource muss sichergestellt werden, dass die Ressource und die von ihr referenzierten Ressourcen alle geladen sind, bevor der Ladevorgang als abgeschlossen gilt.
Basierend auf dieser Prämisse haben wir eine onProgress-Schnittstelle implementiert, die den Fortschritt zurückgibt, der bereits den Ladefortschritt der untergeordneten Ressourcen enthält.
In Code übersetzt:

Klasse Asset {
    laden(beiFortschritt) {
        returniere neues Promise((auflösen) => {
            wenn (Typ von bei Fortschritt !== 'Funktion') {
                beiFortschritt = (_p) => { };
            }

            lass loadedCount = 0;
            let totalCount = 10; // HINWEIS: nur zur Demo
            let onLoaded = () => {
                geladeneAnzahl++;
                beimFortschritt(loadedCount / totalCont);
                wenn (loadedCount === totalCount) auflösen();
            };

            Versprechen.alle(
                dies.refAssets.map(asset => asset.load().then(onLoaded))
            );
        });
    }
}

Wenn wir nun über diese Schnittstelle verfügen und weiterhin die Form der globalen Wartung von loadedCount und totalCount verwenden, wird die Handhabung ziemlich mühsam.
In diesem Artikel wird als Nächstes ein Workaround vorgestellt.

Prinzip

Die Grundidee lautet: Teile und herrsche. Teilen Sie eine große Aufgabe in mehrere kleine Aufgaben auf, berechnen Sie dann den Fortschritt aller kleinen Aufgaben separat und führen Sie schließlich den Fortschritt aller kleinen Aufgaben zusammen, um den Gesamtfortschritt zu ermitteln.
Wie in der folgenden Abbildung dargestellt:

+--------------------------------------------------------------------+
| |
| |
| Gesamtfortschritt |
| |
| +---------+---------+----------+----------+----------+--------+--------+ |
| | Skript1 | Skript2 | Textur1 | Textur2 | Modell1 | Modell2 | |
| | (0~1) | (0~1) | (0~1) | (0~1) | (0~1) | (0~1) | (0~1) | |
| +---------+---------+----------+----------+----------+--------+--------+ |
| |
| Modell1 |
| +-------------+--------------------------+-----------+ |
| | Modell1.json | Material1 | Material2 | |
| | (0~1) | (0~1) | (0~1) | |
| +------------------------+------------------------+ |
| | Textur1 | Textur2 | |
| | (0~1) | (0~1) | |
| +----------+------------+ |
| |
| Modell2 |
| +-------------+--------------------------+-----------+ |
| | Modell2.json | Material1 | Material2 | |
| | (0~1) | (0~1) | (0~1) | |
| +------------------------+------------------------+ |
| | Textur1 | Textur2 | |
| | (0~1) | (0~1) | |
| +----------+------------+ |
| |
+--------------------------------------------------------------------+

Basierend auf diesem Prinzip wird der Fortschritt implementiert, indem der aktuelle Ladefortschritt aller Ressourcen über eine Liste gespeichert und dann bei jedem Auslösen von onProgress ein Zusammenführungsvorgang ausgeführt wird, um den Gesamtfortschritt zu berechnen.

var fortschreitet = [
  0, // Skript1,
  0, // Skript2,
  0, // Textur1,
  0, // Textur2,
  0, // Modell1,
  0, // Modell2
];

Funktion onProgress(p) {
    // TODO: Fortschritte[??] = p;
    Rückgabewert: progresses.reduce((a, b) => a + b, 0) / progresses.length;
}

Doch hier gibt es eine Schwierigkeit. Wenn der onProgress-Rückruf ausgelöst wird, woher wissen wir dann, welches Element in der Liste aktualisiert werden soll?
Mithilfe der Closure-Funktion von JavaScript können wir diese Funktion einfach implementieren.

var schreitet voran = [];
Funktion add() {
    schreitet voran.push(0);
    var index = fortschreitet.länge - 1;

    Rückgabefunktion bei Fortschritt (p) {
        schreitet voran[index] = p;
        reduzieren();
    };
}

Funktion reduzieren() {
    Rückgabewert: progresses.reduce((a, b) => a + b, 0) / progresses.length;
}

Verwenden Sie Closures, um den Index der Ressourcen beizubehalten. Wenn onProgress ausgelöst wird, kann der Fortschritt des entsprechenden Elements in der Liste entsprechend dem Index aktualisiert werden. Der korrekte Fortschritt kann beim abschließenden Zusammenführen berechnet werden.
Jetzt müssen wir nur noch unseren gesamten Code integrieren und testen.

prüfen

Mit dem folgenden Code können wir den gesamten Ladevorgang simulieren:

Klasse Asset {
    Konstruktor(Gesamtzahl) {
        Dies.loadedCount = 0;
        dies.totalCount = Gesamtanzahl;
        diese.timerId = -1;
    }

    laden(beiFortschritt) {
        wenn (Typ von bei Fortschritt !== 'Funktion') {
            beiFortschritt = (_p) => { };
        }

        returniere neues Promise((auflösen) => {
            this.timerId = setInterval(() => {
                dies.loadedCount++;
                beim Fortschritt (dieser.geladeneAnzahl / dieser.Gesamtzahl);
                wenn (dieser.loadedCount === dieser.totalCount) {
                    LöschenInterval(diese.timerId);
                    lösen();
                }
            }, 1000);
        });
    }
}

Klasse Fortschritt {
    Konstruktor(beiFortschritt) {
        dies.onProgress = beim Fortschritt;
        diese._liste = [];
    }

    hinzufügen() {
        diese._list.push(0);

        const index = this._list.length - 1;

        zurückgeben (p) => {
            diese._liste[index] = p;
            dies.reduzieren();
        };
    }

    reduzieren() {
        const p = Math.min(1, diese._list.reduce((a, b) => a + b, 0) / diese._list.length);
        dies.onProgress(p);
    }
}

const p = neuer Fortschritt(console.log);
const asset1 = neues Asset(1);
const asset2 = neues Asset(2);
const asset3 = neues Asset(3);
const asset4 = neues Asset(4);
const asset5 = neues Asset(5);

Versprechen.alles([
    asset1.laden(p.add()),
    asset2.laden(p.add()),
    asset3.laden(p.add()),
    asset4.laden(p.add()),
    asset5.laden(p.add()),
]).then(() => console.log('alle Ressourcen geladen'));

/**
  Ausgabeversprechen { <Status>: "ausstehend" }
  
  0,2 
  0,3 
  0,366666666666666664 
  0,416666666666666663 
  0,456666666666666667 
  0,55666666666666668 
  0,6233333333333333 
  0,6733333333333333 
  0,7133333333333333 
  0,78 
  0,8300000000000001 
  0,869999999999999 
  0,919999999999999 
  0,96 
  1 
  alle Ressourcen geladen 
 */

Der Vorteil dieser Methode besteht darin, dass die globale Verwaltung von loadedCount und totalCount vermieden werden kann und dieser Teil der Arbeit an die interne Verwaltung der Ressourcen zurückgegeben werden kann. Sie muss lediglich große Aufgaben zusammenführen und berechnen.

Die Nachteile liegen ebenfalls auf der Hand und die onProgress-Schnittstelle muss vereinheitlicht werden. Es ist sehr schwierig, in bestehenden Projekten voranzukommen, daher ist es eher für neue oder kleine Projekte geeignet.

Oben sind die Details zur JavaScript-Fortschrittsverwaltung aufgeführt. Weitere Informationen zur JavaScript-Fortschrittsverwaltung finden Sie in den anderen verwandten Artikeln auf 123WORDPRESS.COM!

Das könnte Sie auch interessieren:
  • js realisiert den Fortschrittsprozess mit Pfeilen
  • JS realisiert dynamische Ladeeffekte des Fortschrittsbalkens
  • JavaScript+CSS, um einen Fortschrittsbalkeneffekt zu erzielen
  • JS implementiert einen steuerbaren Fortschrittsbalken
  • js, um einen einfachen Fortschrittsbalkeneffekt zu erzielen
  • Node.js implementiert mehrere Datei-Uploads mit Fortschrittsbalken
  • js+HTML5-Canvas zur Implementierung eines einfachen Ladebalken-Funktionsbeispiels (Fortschrittsbalken)
  • Bringen Sie Ihnen bei, natives JS zu verwenden, um in 3 Minuten eine Datei-Upload-Vorschaukomponente mit Fortschrittsüberwachung zu implementieren
  • Code zur Implementierung eines Download-Fortschrittsbalkens und eines Wiedergabe-Fortschrittsbalkens in JS

<<:  Grafisches Tutorial zur Installation und Konfiguration von MySQL 5.7.21 winx64 unter Windows 10

>>:  Implementierung der Header-Informationen für Nginx-Operationsantworten

Artikel empfehlen

Automatisierte Schnittstellentests mit Postman

Inhaltsverzeichnis Hintergrundbeschreibung Erstel...

Zusammenfassung des Linux-Befehls nc

Der vollständige Name von NC lautet Netcat (Netwo...

Verwenden Sie JS, um Dateien zu bearbeiten (FileReader liest --node's fs)

Inhaltsverzeichnis JS liest Datei FileReader doku...

So stellen Sie ein Angular-Projekt mit Docker bereit

Es gibt zwei Möglichkeiten, Angular-Projekte mit ...

Detaillierte Erklärung der Meta-Tags und ihrer Verwendung in HTML

Ich werde keine weitere Zeit mit Unsinnsgerede ve...

Probleme beim Erstellen von Platzhaltern für HTML-Auswahlfelder

Ich verwende einen Platzhalter in einer Texteinga...

Spezifische Verwendung globaler Variablen von node.js

Globales Objekt Alle Module können aufgerufen wer...

Methodenbeispiel zum sicheren Abrufen tiefer Objekte von Object in Js

Inhaltsverzeichnis Vorwort Text Parameter Beispie...

Die entsprechenden Attribute und Verwendung von XHTML-Tags in CSS

Als ich anfing, Webseiten mit XHTML CSS zu entwer...

SQL-Funktion zum Zusammenführen eines Feldes

Vor kurzem musste ich alle Felder einer verknüpft...

Führen Sie die Schritte aus, um mit Samba Ordner in CentOS 7 freizugeben

Vorwort Samba ist eine kostenlose Software, die d...