Inzicht in de status van je code met de ReportingObserver API

Beëindigde API's vinden in je productie-apps.

ReportingObserver laat je weten wanneer je site een beëindigde API gebruikt of een browserinterventie tegenkomt. De basisfuncties zijn oorspronkelijk geïntroduceerd in Chrome 69. Vanaf Chrome 84 kan de API worden gebruikt in workers.

const observer = new ReportingObserver((reports, observer) => {
  for (const report of reports) {
    console.log(report.type, report.url, report.body);
  }
}, {buffered: true});

observer.observe();

Gebruik de callback om rapporten naar een backend of analyseprovider te sturen voor analyse.

Waarom is dat nuttig? Tot deze API waren waarschuwingen over beëindiging en interventie alleen beschikbaar in DevTools als consoleberichten. Interventies worden alleen geactiveerd door verschillende beperkingen in de echte wereld, zoals apparaat- en netwerkomstandigheden. Je ziet deze berichten misschien nooit als je een site lokaal ontwikkelt of test. ReportingObserver biedt een oplossing voor dit probleem. Als gebruikers in de praktijk potentiële problemen ondervinden, kunnen webontwikkelaars hiervan op de hoogte worden gesteld.

Achtergrond

Een tijdje geleden heb ik een blogpost geschreven (Observing your web app) omdat ik het fascinerend vond hoeveel API's er zijn om de 'dingen' te monitoren die in een web-app gebeuren. Er zijn bijvoorbeeld API's die informatie over de DOM kunnen observeren: ResizeObserver, IntersectionObserver, MutationObserver. PerformanceObserver legt prestatiemetingen vast. En met methoden zoals window.onerror en window.onunhandledrejection weten we zelfs wanneer er iets misgaat.

Er zijn echter andere typen waarschuwingen die niet worden vastgelegd door de bestaande API's. Als je site een beëindigde API gebruikt of een browserinterventie tegenkomt, is DevTools de eerste die je hierover informeert:

Waarschuwingen in de DevTools-console voor beëindigingen en interventies.
Door de browser gestarte waarschuwingen in de DevTools-console.

Je zou denken dat window.onerror deze waarschuwingen vastlegt. Nee. Dat komt omdat window.onerror niet wordt geactiveerd voor waarschuwingen die rechtstreeks door de user-agent zelf worden gegenereerd. Deze wordt geactiveerd voor runtimefouten (JavaScript-uitzonderingen en syntaxisfouten) die worden veroorzaakt door de uitvoering van code.

ReportingObserver neemt het over. Het biedt een programmatic manier om meldingen te krijgen over door de browser uitgegeven waarschuwingen, zoals beëindigingen en interventies. Je kunt de tool gebruiken als rapportagetool en je hoeft je minder zorgen te maken of gebruikers onverwachte problemen tegenkomen op je live site.

De API

ReportingObserver lijkt op de andere Observer-API's, zoals IntersectionObserver en ResizeObserver. Je geeft het een callback en het geeft je informatie. De informatie die de callback krijgt, is een lijst met problemen die de pagina heeft veroorzaakt:

const observer = new ReportingObserver((reports, observer) => {
  for (const report of reports) {
    // → report.type === 'deprecation'
    // → report.url === 'https://reporting-observer-api-demo.glitch.me'
    // → report.body.id === 'XMLHttpRequestSynchronousInNonWorkerOutsideBeforeUnload'
    // → report.body.message === 'Synchronous XMLHttpRequest is deprecated...'
    // → report.body.lineNumber === 11
    // → report.body.columnNumber === 22
    // → report.body.sourceFile === 'https://reporting-observer-api-demo.glitch.me'
    // → report.body.anticipatedRemoval === <JS_DATE_STR> or null
  }
});

observer.observe();

Gefilterde rapporten

Rapporten kunnen vooraf worden gefilterd om alleen bepaalde rapporttypen te bekijken. Op dit moment zijn er 2 rapporttypen: 'deprecation' en 'intervention'.

const observer = new ReportingObserver((reports, observer) => {
  …
}, {types: ['deprecation']});

Gebufferde rapporten

Gebruik de optie buffered: true als je de rapporten wilt zien die zijn gegenereerd voordat de observer-instantie werd gemaakt:

const observer = new ReportingObserver((reports, observer) => {
  …
}, {types: ['intervention'], buffered: true});

Deze optie is ideaal voor situaties zoals het lazy-loaden van een bibliotheek die een ReportingObserver gebruikt. De waarnemer wordt laat toegevoegd, maar je mist niets wat eerder is gebeurd tijdens het laden van de pagina.

Stoppen met observeren

Stop de observatie met de methode disconnect():

observer.disconnect();

Voorbeelden

Browserinterventies melden aan een analyseprovider

const observer = new ReportingObserver((reports, observer) => {
  for (const report of reports) {
    sendReportToAnalytics(JSON.stringify(report.body));
  }
}, {types: ['intervention'], buffered: true});

observer.observe();

Meldingen krijgen wanneer API's worden verwijderd

const observer = new ReportingObserver((reports, observer) => {
  for (const report of reports) {
    if (report.type === 'deprecation') {
      sendToBackend(`Using a deprecated API in ${report.body.sourceFile} which will be
                     removed on ${report.body.anticipatedRemoval}. Info: ${report.body.message}`);
    }
  }
});

observer.observe();

Conclusie

ReportingObserver biedt je een extra manier om potentiële problemen in je web-app te ontdekken en te monitoren. Het is zelfs een handige tool om inzicht te krijgen in de status van je codebase (of het gebrek daaraan). Stuur rapporten naar een backend, weet wat de echte problemen zijn, update de code en doe er je voordeel mee.

Toekomstige activiteiten

Ik hoop dat ReportingObserver in de toekomst de de facto API wordt om alle soorten problemen in JavaScript op te sporen. Stel je voor dat er één API is die alles vangt wat er misgaat in je app:

  • Browserinterventies
  • Beëindigingen
  • Schendingen van het Functiebeleid. Ga naar Chromium-probleem 867471.
  • JS-uitzonderingen en -fouten (worden op dit moment afgehandeld door window.onerror).
  • Niet-afgehandelde JS-promise-afwijzingen (worden op dit moment afgehandeld door window.onunhandledrejection)

Meer bronnen:

Hero-afbeelding door Sieuwert Otterloo op Unsplash.