CocosCreator ScrollView-Optimierungsreihe: Frame-Laden

CocosCreator ScrollView-Optimierungsreihe: Frame-Laden

1. Einleitung

JS ist ein Single-Thread-System, was bedeutet, dass alle Aufgaben in die Warteschlange gestellt werden müssen und die nächste Aufgabe erst ausgeführt wird, wenn die aktuelle Aufgabe abgeschlossen ist. Wenn die vorherige Aufgabe lange dauert, muss die nächste Aufgabe warten.

Cocos Creator wird mit Java Script/Type Script entwickelt, das im Wesentlichen JS ist und auch über die oben genannten Funktionen verfügt. Insbesondere bei unsachgemäßer Verwendung kann es sehr wahrscheinlich zu Verzögerungen an der Benutzeroberfläche kommen.

Wenn Sie beispielsweise 500 Knoten für den Inhalt einer ScrollView erstellen, kann die folgende Schnittstelle hängen bleiben:

PS: Während des Ladevorgangs gab es ein Dialogfeld zum Laden, das aber anscheinend nie angezeigt wurde, weil es hängen blieb.

In diesem Artikel erfahren Sie, wie Sie die oben genannten Probleme mithilfe der „Frame Loading“ -Technologie lösen können. Der endgültige Effektvergleich ist wie folgt:

2. Analyse des festgefahrenen Problems

Unter normalen Umständen kann der Code wie folgt aussehen, wenn wir eine bestimmte Anzahl untergeordneter Knoten für ScrollView erstellen

public directLoad(Länge: Zahl) {
    für (sei i = 0; i < Länge; i++) {
        dies._initItem(i);
    }
}
 
private _initItem(itemIndex: Zahl) {
    : Lassen Sie itemNode = cc.instantiate(this.itemPrefab);
    itemNode.width = diese.scrollView.content.width / 10;
    itemNode.Höhe = itemNode.Breite;
    itemNode.parent = dieser.scrollView.content;
    itemNode.setPosition(0, 0);
}

Im Allgemeinen scheint das Programm bei einer sehr kleinen Länge, z. B. 10, während der Ausführung einwandfrei zu laufen. Bei genauerer Beobachtung werden Sie jedoch feststellen, dass es eine Weile hängen bleibt, dann aber schnell endet.

Insbesondere wenn der Wert der Länge einen bestimmten Wert erreicht, z. B. 50+, wird dieser Code wie im Screenshot oben angezeigt angezeigt - stecken geblieben

Letztendlich besteht das Problem darin, dass die zum Erstellen eines Knotens über cc.instantiate und setParent für diesen Knoten erforderliche Zeit nicht so kurz ist wie gedacht und natürlich auch nicht so lang wie gedacht. Wenn jedoch kontinuierlich eine bestimmte Anzahl von Knoten erstellt wird, wird das Problem größer, d. h., das Erstellen des Knotens kann einige Zeit dauern.

Wenn wir dieses Problem visueller verstehen möchten, könnte es wie das folgende Bild aussehen.

Direkte Belastung

Gemäß der obigen Abbildung sind die Frames 1 bis 4 offensichtlich vollständig belegt, was dazu führt, dass die Ausführung aller anderen Logik während dieses Zeitraums fehlschlägt (das Dialogfeld „Laden“ kann nicht angezeigt werden, die Rotationsanimation bleibt hängen usw.).

Wie kann man das Problem also lösen?

3. Lösung (theoretisch)

Einige Studenten denken vielleicht daran, Promise zu verwenden, um das Problem asynchron zu lösen. In diesem Fall platziert Promise jedoch nur den roten Code, der kontinuierlich Knoten erstellt, die etwas später ausgeführt werden sollen. Wenn der rote Code jedoch ausgeführt wird, bleibt er während dieser Zeitspanne immer noch hängen, sodass Promise mit dieser Situation nicht fertig wird.

Wie sollen wir es also lösen?

Eine davon ist das, worüber wir heute sprechen werden: „Frame Loading“ . Was verstehen wir unter „Frame Loading“?

Wie immer hier das Bild:

Rahmenlast

Mit dem obigen Bild ist es einfacher, "Frame-Laden" zu verstehen. Der spezifische Ausführungsprozess ist wie folgt

  1. Teilen Sie zunächst den zeitaufwändigen und festgefahrenen Code in viele kleine Abschnitte auf
  2. Dann nehmen Sie sich für jeden Frame etwas Zeit, um diese kleinen Segmente auszuführen
  3. Auf diese Weise bleibt Zeit, damit in jedem Frame andere Logik ausgeführt werden kann (damit das Dialogfeld „Laden“ angezeigt und die Rotationsanimation fortgesetzt werden kann).

OK, die Theorie ist klar, aber wie setzen wir es in der Praxis um?

Zum Beispiel:

  1. Wie kann der Code in viele kleine Abschnitte aufgeteilt werden?
  2. Wie kann man in jedem Frame etwas Zeit einplanen, um diese kleinen Segmente auszuführen?

Derzeit müssen wir den Coroutine- Generator von ES6 (ES2015) verwenden, um dies zu erreichen.

4. Lösung (Code)

Am Beispiel des Codes, den wir im zweiten Abschnitt verwendet haben (Erstellen einer bestimmten Anzahl untergeordneter Knoten für ScrollView), implementieren wir den Code in mehrere kleine Segmente und weisen in jedem Frame etwas Zeit für die Ausführung dieser kleinen Segmente zu.

4.1 Verwenden Sie den Generator, um den Code in mehrere kleine Abschnitte aufzuteilen

Vor der Teilung:

public directLoad(Länge: Zahl) {
    für (sei i = 0; i < Länge; i++) {
        dies._initItem(i);
    }
}
 
private _initItem(itemIndex: Zahl) {
    : Lassen Sie itemNode = cc.instantiate(this.itemPrefab);
    itemNode.width = diese.scrollView.content.width / 10;
    itemNode.Höhe = itemNode.Breite;
    itemNode.parent = dieser.scrollView.content;
    itemNode.setPosition(0, 0);
}

Nach dem Teilen:

/**
 * (Neuer Code) Holen Sie sich den Generator, der den untergeordneten Knoten generiert
 */
private *_getItemGenerator(Länge: Zahl) {
    für (sei i = 0; i < Länge; i++) {
        erreiche dies._initItem(i);
    }
}
 
/**
 * (derselbe Code wie vor der Aufteilung)
 */
private _initItem(itemIndex: Zahl) {
    : Lassen Sie itemNode = cc.instantiate(this.itemPrefab);
    itemNode.width = diese.scrollView.content.width / 10;
    itemNode.Höhe = itemNode.Breite;
    itemNode.parent = dieser.scrollView.content;
    itemNode.setPosition(0, 0);
}

Das Prinzip besteht hier darin, mit Generator alle Knoten in einer For-Schleife zu erstellen und jeden Schritt der For-Schleife in ein kleines Segment aufzuteilen.

Natürlich kann dieser „Split“-Code nicht ausgeführt werden, da er nur den Splitting-Schritt implementiert. Damit er ausgeführt werden kann, benötigen wir den zweiten Code unten

4.2 Planen Sie pro Frame etwas Zeit für die Ausführung ein

Schauen wir uns das Bild an, das wir gerade aufgenommen haben.

Rahmenlast

Mit dem Diagramm wird der resultierende Code

/**
 * Frame-Laden implementieren*/
async framingLoad(Länge: Zahl) {
    warte auf this.executePreFrame(this._getItemGenerator(length), 1);
}
 
/**
 * Generatorlogik in Frames ausführen*
 * @param Generator Generator * @param Dauer Dauer (ms)
 * Bei jeder Ausführung des Generatorvorgangs die maximale Ausführungsdauer.
 * Angenommen, der Wert beträgt 8 ms, bedeutet dies, dass in 1 Frame (insgesamt 16 ms) 8 ms für diese Logikausführung reserviert sind*/
private executePreFrame(Generator: Generator, Dauer: Zahl) {
    returniere neues Promise((lösen, ablehnen) => {
        sei gen = Generator;
        // Ausführungsfunktion erstellen let execute = () => {
 
            // Vor der Ausführung den Startzeitstempel aufzeichnen let startTime = new Date().getTime();
 
            // Dann weiterhin die aufgeteilten Codesegmente vom Generator holen und ausführen for (let iter = gen.next(); ; iter = gen.next()) {
 
                // Prüfen, ob alle Generatoren ausgeführt wurden // Wenn ja, ist die Aufgabe abgeschlossen if (iter == null || iter.done) {
                    lösen();
                    zurückkehren;
                }
 
                // Nachdem jedes kleine Codesegment ausgeführt wurde, prüfen wir, ob // die maximale Ausführungszeit überschritten wurde, die wir diesem Frame für diese kleinen Codesegmente zugewiesen haben, if (new Date().getTime() - startTime > duration) {
                    
                    // Wenn das Limit überschritten wird, wird der aktuelle Frame nicht ausgeführt. Starten Sie den Timer und führen Sie den nächsten Frame aus this.scheduleOnce(() => {
                        ausführen();
                    });
                    zurückkehren;
                }
            }
        };
 
        // Führen Sie die Ausführungsfunktion aus, execute();
    });
}
 

Der Code ist ausführlich kommentiert, einige Punkte sind jedoch erwähnenswert:

  1. Um zu wissen, ob diese kleinen Aufgaben erledigt wurden, verwende ich Promise. Wenn sie erledigt sind, resolve
  2. Die Ausführungszeit jedes kleinen Codesegments ist möglicherweise nicht festgelegt und überschreitet möglicherweise unsere erwartete Zeit. Beispielsweise erwarten wir, dass wir 1 ms pro Frame zuweisen, um diese kleinen Codesegmente auszuführen. Angenommen, die Ausführungszeit jedes der ersten drei kleinen Codesegmente beträgt 0,2 ms, 0,5 ms und 0,4 ms. Dann werden in dem von mir angegebenen Code diese drei kleinen Codesegmente ausgeführt und dann wird der aktuelle Frame beendet, um mit der Ausführung dieser kleinen Codesegmente fortzufahren, da der Zeitaufwand hier bereits 1,1 ms beträgt, was 0,1 ms mehr ist als die 1 ms, die ich festgelegt habe. Natürlich können Sie den Code selbst ändern, damit diese Ausführungen strikt innerhalb der maximalen Zeitspanne von 1 ms erfolgen und keine Zeitüberschreitung bei der Ausführung auftritt (d. h. das dritte kleine Segment wird nicht mehr ausgeführt).

Bisher haben wir bis zu einem gewissen Grad "Frame Loading" erreicht ~

Alle Diagramme und Codes in diesem Projekt befinden sich im Github-Repository. Wenn Sie eine Überprüfung durchführen müssen, können Sie das Projekt direkt herunterladen, ohne den Code selbst überprüfen zu müssen.

👉👉https://github.com/zhitaocai/CocosCreator-ScrollVIewPlus👈👈

V. Fazit

  1. Obwohl unser Titel „ScrollView-Optimierungsreihe“ lautet, tendiere ich eher zu „Verwenden Sie das Laden von Frames, um ScrollView zu optimieren“. In diesem Artikel geben wir als Beispiel das Erstellen von Knoten, aber ich sage bewusst nicht „Split-Frame-Erstellung“, da ich denke, dass 「分幀加載」 eine Lösung zur Leistungsoptimierung ist , die „Split-Frame-Erstellung“, „Split-Frame-Operation“, „Split-Frame-Berechnung“, „Split-Frame-Rendering“ usw. sein kann.
  2. Bei der Implementierung des Framings haben wir die Funktion this.scheduleOnce verwendet, aber Sie können tatsächlich versuchen, sie bei update(dt:number) auszuführen. Versuchen wir, mein „Testprojekt“ zu ändern, um es zu überprüfen~
  3. Um Generator in TypeScript zu verwenden, müssen Sie auch tsconfig.json im Cocos-Projekt ändern: Fügen Sie es2015 zum Array compilerOptions.lib hinzu

Oben sind die Details zum Frame-Laden der CocosCreator ScrollView-Optimierungsreihe aufgeführt. Weitere Informationen zum Frame-Laden der CocosCreator ScrollView-Optimierung finden Sie in den anderen verwandten Artikeln auf 123WORDPRESS.COM!

Das könnte Sie auch interessieren:
  • Cocos-Ersteller-Touch-Event-Anwendung (Beispiel: Berühren, um mehrere untergeordnete Knoten auszuwählen)
  • So fügen Sie mit cocos2d Touch-Ereignisse in der iOS-Entwicklung hinzu
  • Beispiel für ein Cocos2d-x-Touch-Ereignis
  • Detaillierte Erklärung der CocosCreator-Optimierung DrawCall
  • CocosCreator implementiert Skill-Kühleffekt
  • Detaillierte Erklärung des Cocoscreater-Prefabs
  • So verwenden Sie residente Knoten für die Ebenenverwaltung in CocosCreator
  • So verwenden Sie CocosCreator zur Tonverarbeitung bei der Spieleentwicklung
  • Detaillierte Erklärung, wie CocosCreator-Systemereignisse generiert und ausgelöst werden

<<:  Detaillierte Erläuterung der allgemeinen Schritte zur SQL-Anweisungsoptimierung

>>:  So überprüfen Sie die Festplattennutzung unter Linux

Artikel empfehlen

Detaillierte Erklärung von :key in VUE v-for

Wenn der Schlüssel nicht zum v-for-Tag hinzugefüg...

XHTML-Einführungstutorial: Webseitenkopf und DTD

Obwohl Kopf und DTD nicht auf der Seite angezeigt...

So verwenden Sie Echarts zum Visualisieren von Komponenten in Vue

Offizielle Website-Adresse der Echarts-Komponente...

Lösung für den Fehler beim Starten von MySQL

Lösung für den Fehler beim Starten von MySQL MySQ...

Der Unterschied zwischen HTML Empty Link href="#" und href="javascript:void(0)"

# enthält eine Standortinformation. Der Standardan...

Implementierung von Check Constraints in MySQL 8.0

Hallo zusammen, ich bin Tony, ein Lehrer, der nur...

JavaScript-Canvas zum Erzielen eines Regentropfeneffekts

In diesem Artikelbeispiel wird der spezifische Co...

Detaillierte Erklärung der RPM-Installation in MySQL

Installation und Deinstallation anzeigen # rpm -q...

Lösung für die falsche Ausrichtung des Eingabecursors in Chrome, Firefox und IE

Detaillierte Erklärung zur Fehlplatzierung des Ein...

Lösung für den internen Serverfehler Nginx 500

Als ich heute Nginx verwendete, trat ein 500-Fehl...

Grafisches Tutorial zur Installation und Konfiguration von MySQL 8.0.22 winx64

Das Tutorial zur Datenbankinstallation von MySQL-...