Teilen von Front-End-Technologie: Überprüfung von Problemen bei der Optimierung der Seitenleistung

Hintergrund des Projekts

Im code_pc-Projekt muss das Frontend rrweb verwenden, um die Lehrinhalte des Lehrers aufzuzeichnen, und die Schüler können diese aufzeichnen und wiedergeben. Um die Größe der Aufzeichnungsdatei zu reduzieren, besteht die aktuelle Aufzeichnungsstrategie darin, zuerst einen vollständigen Snapshot und dann inkrementelle Snapshots aufzuzeichnen. Die Aufzeichnungsphase überwacht tatsächlich DOM-Elementänderungen über MutationObserver und schiebt dann Ereignisse nacheinander in das Array .

Zur dauerhaften Speicherung können die aufgezeichneten Daten komprimiert und in eine JSON-Datei serialisiert werden. Der Lehrer fügt die JSON-Datei in das Kursunterlagenpaket ein, komprimiert sie in ein komprimiertes Paket und lädt es in das Bildungsverwaltungssystem hoch. Wenn die Schüler abspielen, lädt das Front-End zunächst das komprimierte Paket herunter, dekomprimiert es über JSZip, ruft die JSON-Datei ab, deserialisiert und dekomprimiert sie, ruft die ursprünglichen Aufnahmedaten ab und übergibt sie dann an rrwebPlayer, um die Aufnahmewiedergabe zu implementieren.

Problem gefunden

Während der Projektentwicklungsphase sind Testaufnahmen nicht zu lang, sodass die Aufnahmedatei nicht groß ist (einige hundert KB) und die Wiedergabe relativ reibungslos verläuft. Als das Projekt jedoch in die Testphase eintrat und die Aufzeichnung einer langen Unterrichtsszene simuliert wurde, stellte sich heraus, dass die Aufnahmedatei sehr groß wurde und 10 bis 20 MB erreichte. QA-Studenten berichteten, dass beim Öffnen der Schüler-Wiedergabeseite die Seite Offensichtlich steckte es fest und die Einfrierzeit lag zwischen mehr als 20 Sekunden. Während dieses Zeitraums erfolgt keine Reaktion auf Seiteninteraktionsereignisse.

Die Seitenleistung ist der Hauptfaktor, der sich auf die Benutzererfahrung auswirkt. Es ist offensichtlich inakzeptabel, dass die Seite über einen so langen Zeitraum einfriert.

Fehlerbehebung

Nach der Kommunikation innerhalb der Gruppe haben wir erfahren, dasszwei Hauptfaktoren zu Seitenverzögerungen führen können: Front-End-Dekomprimierung von Zip-Paketen , und die Aufnahme-Wiedergabedatei wird geladen. Mein Kollege vermutete, dass es sich hauptsächlich um ein Problem mit der Dekomprimierung des Zip-Pakets handelte, und hoffte, dass ich versuchen würde, den Dekomprimierungsprozess in einen Arbeitsthread zu verlagern. Stimmt es also, wie meine Kollegen sagten, dass die Front-End-Dekomprimierung des Zip-Pakets dazu führt, dass die Seite einfriert?

3.1 Lösen Sie die zeitaufwändigen Probleme, die durch die rekursiven komplexen Objekte von Vue verursacht werden

In Bezug auf das Problem des Einfrierens von Seiten fällt mir zunächst ein, dass es durch Thread-Blockierung verursacht werden muss. Daher müssen wir untersuchen, wo lange Aufgaben auftreten.

Die sogenannten langen Aufgaben beziehen sich auf Aufgaben, deren Ausführung mehr als 50 ms dauert. Wie wir alle wissen, verwenden das Seitenrendering des Chrome-Browsers und die V8-Engine einen Thread. Wenn die Ausführung des JS-Skripts zu lange dauert, wird der Rendering-Thread blockiert , wodurch die Seite einfriert. .

Für die zeitaufwändige Analyse der JS-Ausführung sollte jeder wissen, wie man das Leistungspanel verwendet. Analysieren Sie im Leistungsbereich den Aufrufstapel und die Ausführungszeit, indem Sie sich das Flame-Diagramm ansehen. Die Breite jedes Kästchens im Flammendiagramm stellt die Ausführungszeit dar, und die Höhe der gestapelten Blöcke stellt die Tiefe des Aufrufstapels dar.

Dieser Idee folgend werfen wir einen Blick auf die Ergebnisse der Analyse:
[Externer Link Bilder werden übertragen...(img-nfpBonig_convert/61cbb6f6f8d1d2e7b232fc791ca00e4c.png)
Wie Sie sehen, ist replayRRweb offensichtlich eine lange Aufgabe, die fast 18 Sekunden dauert und den Hauptthread ernsthaft blockiert.

Die lange Zeit, die replayRRweb benötigt, wird durch zwei interne Aufrufe verursacht, nämlich den hellgrünen Teil links und den dunkelgrünen Teil rechts. Schauen wir uns den Aufrufstapel an, um zu sehen, wo der Zeitverbrauch am größten ist:
[Externer Link Bilder werden übertragen...(img-Gthgovert/0302be66a0743642bbb24c0111ba5eb6.png)
Studenten, die mit dem Vue-Quellcode vertraut sind, haben möglicherweise bemerkt, dass die oben genannten zeitaufwändigen Methoden alle rekursive und reaktionsfähige Methoden innerhalb von Vue sind (diese rechts gezeigten Methoden stammen von vue.runtime.esm.js).

Warum belegen diese Methoden lange Zeit den Hauptthread? Es gibt einen Artikel zur Vue-Leistungsoptimierung:Werfen Sie keine komplexen Objekte in Daten, sonst durchläuft Vue die Eigenschaften im Objekt tiefgreifend, um Getter hinzuzufügen Setter (auch wenn diese Daten nicht für das Rendern der Ansicht benötigt werden), was zu Leistungsproblemen führt.

Gibt es also ein solches Problem im Geschäftscode? Wir haben einensehr verdächtigen Code gefunden:

export default {
   
    
    
  data() {
   
    
    
    return {
   
    
    
      rrWebplayer: null
    }
  },
  mounted() {
   
    
    
    bus.$on("setRrwebEvents", (eventPromise) => {
   
    
    
      eventPromise.then((res) => {
   
    
    
        this.replayRRweb(JSON.parse(res));
      })
    })
  }, methods: {
   
    
    
    replayRRweb(eventsRes) {
   
    
    
      this.rrWebplayer = new rrwebPlayer({
   
    
    
        target: document.getElementById('replayer'),
        props: {
   
    
    
          events: eventsRes,
          unpackFn: unpack,
          // ...
        }
      })
    }
  }
}

Im obigen Code wird eine rrwebPlayer-Instanz erstellt und den Reaktionsdaten von rrWebplayer zugewiesen. Beim Erstellen der Instanz wurde auch ein Array eventsRes akzeptiert. Dieses Array ist sehr groß und enthält Zehntausende Daten.

Wenn Vue in diesem Fall rekursiv auf rrWebplayer antwortet, muss dies sehr zeitaufwändig sein. Daher müssen wir rrWebplayer in nicht reaktive Daten ändern (um die rekursive Reaktivität von Vue zu vermeiden).

In nicht reaktive Daten konvertierenEs gibt drei Hauptmethoden:

Die Daten sind nicht in der Datenoption vordefiniert, sondern werden dynamisch definiert, nachdem die Komponenteninstanz erstellt wurde. this.rrwebPlayer

Guess you like

Origin blog.csdn.net/youdaotech/article/details/122879678