JavaScript-Code mit hoher Auslastung identifizieren

JavaScript mit hoher Auslastung kann sich negativ auf die Seitenaufbauleistung und die Interaktivität auswirken. Moderne Webanwendungen sind mehr denn je von JavaScript aus mehreren Quellen abhängig. Dazu gehören der Anwendungscode selbst (und der Framework-Code, auf dem er basiert) sowie Drittanbieter-Skripts, die Funktionen wie Chat-Widgets und Videoplayer hinzufügen. Analyse- und Marketingskripts im Hintergrund sind ebenfalls häufige Ursachen, die leicht vergessen werden.

Die Ursachen für eine nicht reagierende Webseite zu ermitteln, kann schwierig sein. Für das Tracing oder Profiling der Webleistung und die Interpretation der Ergebnisse ist ein gewisses Fachwissen erforderlich. Außerdem unterscheiden sich Felddaten oft stark von Labordaten, die nur einen kleinen Teil der realen Nutzerszenarien abbilden. Das kann es schwierig machen, die Ursachen für eine schlechte Leistung zu ermitteln, insbesondere bei Interaktionen.

Die Long Animation Frames API ist eine einfache API, mit der sich rechenintensive JavaScript-Aufgaben in der Praxis identifizieren lassen. Ein rechenintensives Script kann entweder ein einzelnes Script mit langer Laufzeit oder ein Script sein, das während des Seitenlebenszyklus mehrmals ausgeführt wird.

Implementierung

Long Animation Frames werden über die PerformanceObserver-Schnittstelle überwacht. Es wird ein long-animation-frame-Eintrag ausgegeben, wenn das Rendern eines Animationsframes länger als 50 ms dauert. Der Eintrag enthält Informationen zum Long Animation Frame, einschließlich der Dauer des Frames und der Scripts, die während des Frames ausgeführt wurden.

Der Eintrag long-animation-frame enthält ein Attribut scripts, das ein Array von PerformanceScript-Objekten ist. Jedes PerformanceScript-Objekt enthält Informationen zum Skript, das während des Long Animation Frame ausgeführt wurde, einschließlich sourceURL und duration des Skripts.

Beispiel für die Identifizierung der am längsten laufenden Skripts, die zu Long Animation Frames beitragen

// Accumulate all script entries across the page lifecycle so no
// data is lost between observer callbacks.
const allScripts = [];

const observer = new PerformanceObserver(list => {
  // Collect all script entries across frames to find the biggest offenders.
  allScripts.push(...list.getEntries().flatMap(entry => entry.scripts));

  // Group by sourceURL so you can identify which scripts contribute
  // the most total time, even if each individual invocation is short.
  const scriptSource = [...new Set(allScripts.map(script => script.sourceURL))];
  const scriptsBySource = scriptSource.map(sourceURL => ([sourceURL,
      allScripts.filter(script => script.sourceURL === sourceURL)
  ]));
  const processedScripts = scriptsBySource.map(([sourceURL, scripts]) => ({
    sourceURL,
    count: scripts.length,
    totalDuration: scripts.reduce((subtotal, script) => subtotal + script.duration, 0)
  }));

  // Only include scripts above a certain threshold to reduce noise.
  const heavyScripts = processedScripts.filter(script => {
    return script.totalDuration > 100;
  });

  // Sort by total duration so the worst offenders appear first,
  // making it easier to prioritize optimization efforts.
  heavyScripts.sort((a, b) => b.totalDuration - a.totalDuration);

  // Log to the console for local debugging. In production, replace
  // this with a call to send the data to your analytics service.
  console.table(heavyScripts);
});

// Use buffered: true to capture any long frames that occurred before
// this observer was registered.
observer.observe({type: 'long-animation-frame', buffered: true});

Best Practices

  • EMPFOHLEN: Bevorzugen Sie die Long Animation Frames API gegenüber Alternativen wie der JS Self-Profiling API, die einen höheren Laufzeitaufwand verursacht.
  • DO summarize the key information as the Long Animation Frames API contains a lot of detail.
  • DO send the required information to an analytics service in production.

Browserunterstützung und Fallback-Strategien

Die Long Animation Frames API wird von Browsern, die sie nicht unterstützen, ignoriert. Sie kann daher ohne Fallbacks verwendet werden. In den meisten Fällen gelten die ermittelten Optimierungsmöglichkeiten auch für andere Browser.