Paginalevenscyclus-API

Browser Support

  • Chroom: 68.
  • Rand: 79.
  • Firefox: niet ondersteund.
  • Safari: niet ondersteund.

Moderne browsers onderbreken tegenwoordig soms pagina's of verwijderen ze volledig wanneer de systeembronnen beperkt zijn. In de toekomst willen browsers dit proactief doen, zodat ze minder stroom en geheugen verbruiken. De Page Lifecycle API biedt lifecycle-hooks, zodat uw pagina's deze browserinterventies veilig kunnen verwerken zonder de gebruikerservaring te beïnvloeden. Bekijk de API om te zien of u deze functies in uw applicatie moet implementeren.

Achtergrond

De levenscyclus van applicaties is een belangrijke manier waarop moderne besturingssystemen resources beheren. Op Android, iOS en recente Windows-versies kunnen apps op elk moment door het besturingssysteem worden gestart en gestopt. Dit stelt deze platforms in staat om resources te stroomlijnen en opnieuw toe te wijzen waar ze de gebruiker het meest ten goede komen.

Op het web bestond een dergelijke levenscyclus historisch gezien niet en apps kunnen onbeperkt in gebruik blijven. Wanneer er een groot aantal webpagina's actief is, kunnen kritieke systeembronnen zoals geheugen, CPU, batterij en netwerk overbelast raken, wat leidt tot een slechte gebruikerservaring.

Hoewel het webplatform al lang gebeurtenissen bevat die betrekking hebben op levenscyclusstatussen – zoals load , unload en visibilitychange – stellen deze gebeurtenissen ontwikkelaars alleen in staat om te reageren op door de gebruiker geïnitieerde wijzigingen in de levenscyclusstatus. Om ervoor te zorgen dat het web betrouwbaar werkt op apparaten met een laag stroomverbruik (en over het algemeen resource-bewuster is op alle platforms), hebben browsers een manier nodig om proactief systeembronnen terug te winnen en opnieuw toe te wijzen.

Browsers nemen tegenwoordig al actieve maatregelen om bronnen te besparen voor pagina's in tabbladen op de achtergrond. Veel browsers (vooral Chrome) willen dit nog veel meer doen om hun totale bronnengebruik te verkleinen.

Het probleem is dat ontwikkelaars zich niet kunnen voorbereiden op dit soort door het systeem geïnitieerde interventies, of zelfs maar weten dat ze plaatsvinden. Dit betekent dat browsers voorzichtig moeten zijn, anders lopen ze het risico webpagina's te beschadigen.

De Page Lifecycle API probeert dit probleem op de volgende manier op te lossen:

  • Introductie en standaardisatie van het concept van levenscyclusstatussen op het web.
  • Het definiëren van nieuwe, door het systeem geïnitieerde statussen waarmee browsers de bronnen kunnen beperken die door verborgen of inactieve tabbladen kunnen worden verbruikt.
  • Het creëren van nieuwe API's en gebeurtenissen waarmee webontwikkelaars kunnen reageren op overgangen van en naar deze nieuwe, door het systeem geïnitieerde toestanden.

Deze oplossing biedt de voorspelbaarheid die webontwikkelaars nodig hebben om applicaties te bouwen die bestand zijn tegen systeeminterventies. Bovendien kunnen browsers hiermee systeembronnen agressiever optimaliseren, wat uiteindelijk alle internetgebruikers ten goede komt.

De rest van dit bericht introduceert de nieuwe functies voor de paginalevenscyclus en onderzoekt hoe deze zich verhouden tot alle bestaande statussen en gebeurtenissen van het webplatform. Het geeft ook aanbevelingen en best practices voor de soorten werk die ontwikkelaars wel (en niet) zouden moeten doen in elke status.

Overzicht van paginalevenscyclusstatussen en -gebeurtenissen

Alle levenscyclusstatussen van pagina's zijn afzonderlijk en sluiten elkaar uit, wat betekent dat een pagina zich slechts in één status tegelijk kan bevinden. De meeste wijzigingen in de levenscyclusstatus van een pagina zijn over het algemeen zichtbaar via DOM-gebeurtenissen (zie de aanbevelingen van ontwikkelaars voor elke status voor de uitzonderingen).

De makkelijkste manier om de levenscyclusstatussen van pagina's uit te leggen, en ook de gebeurtenissen die de overgangen tussen deze statussen aangeven, is misschien wel met behulp van een diagram:

Een visuele weergave van de status en gebeurtenisstroom die in dit document worden beschreven.
API-status en gebeurtenisstroom van de paginalevenscyclus.

Staten

De volgende tabel geeft een gedetailleerde beschrijving van elke status. Ook worden de mogelijke statussen voor en na de status weergegeven, evenals de gebeurtenissen die ontwikkelaars kunnen gebruiken om veranderingen te observeren.

Staat Beschrijving
Actief

Een pagina is actief als deze zichtbaar is en de invoerfocus heeft.

Mogelijke voorgaande toestanden:
passief (via de focus )
bevroren (via de resume -gebeurtenis, vervolgens de pageshow gebeurtenis)

Mogelijke volgende toestanden:
passief (via het blur -event)

Passief

Een pagina bevindt zich in de passieve status als deze zichtbaar is en geen invoerfocus heeft.

Mogelijke voorgaande toestanden:
actief (via de blur -gebeurtenis)
verborgen (via de visibilitychange -gebeurtenis)
bevroren (via de resume -gebeurtenis, vervolgens de pageshow gebeurtenis)

Mogelijke volgende toestanden:
actief (via de focus )
verborgen (via de visibilitychange -gebeurtenis)

Verborgen

Een pagina is verborgen als deze niet zichtbaar is (en niet is bevroren, verwijderd of beëindigd).

Mogelijke voorgaande toestanden:
passief (via de visibilitychange -gebeurtenis)
bevroren (via de resume -gebeurtenis, vervolgens de pageshow gebeurtenis)

Mogelijke volgende toestanden:
passief (via de visibilitychange -gebeurtenis)
bevroren (via het freeze )
weggegooid (geen gebeurtenissen afgevuurd)
beëindigd (geen gebeurtenissen afgevuurd)

Bevroren

In de bevroren toestand schort de browser de uitvoering van bevriesbare taken in de taakwachtrijen van de pagina op totdat de pagina weer wordt ontdooid. Dit betekent dat JavaScript-timers en fetch-callbacks niet worden uitgevoerd. Reeds actieve taken kunnen worden voltooid (met name de freeze -callback), maar ze kunnen beperkt zijn in wat ze kunnen doen en hoe lang ze kunnen worden uitgevoerd.

Browsers bevriezen pagina's om CPU-/batterij-/dataverbruik te besparen. Ze doen dit ook om sneller vooruit en achteruit te kunnen navigeren , zodat de pagina niet opnieuw geladen hoeft te worden.

Mogelijke voorgaande toestanden:
verborgen (via het freeze -evenement)

Mogelijke volgende toestanden:
actief (via de resume gebeurtenis, vervolgens de pageshow gebeurtenis)
passief (via de resume gebeurtenis, vervolgens de pageshow gebeurtenis)
verborgen (via het resume evenement)
weggegooid (geen gebeurtenissen afgevuurd)

Beëindigd

Een pagina bevindt zich in de beëindigde status zodra de browser is begonnen met het uitladen en wissen van de pagina uit het geheugen. In deze status kunnen geen nieuwe taken meer worden gestart en taken die al bezig zijn, kunnen worden beëindigd als ze te lang duren.

Mogelijke voorgaande toestanden:
verborgen (via de pagehide -gebeurtenis)

Mogelijke volgende toestanden:
GEEN

Weggegooid

Een pagina bevindt zich in de verwijderde status wanneer deze door de browser wordt verwijderd om resources te besparen. In deze status kunnen geen taken, event callbacks of JavaScript worden uitgevoerd, omdat verwijderingen doorgaans plaatsvinden onder beperkte resourcebeperkingen, waardoor het onmogelijk is om nieuwe processen te starten.

In de verwijderde status is het tabblad zelf (inclusief de tabbladtitel en favicon) doorgaans nog zichtbaar voor de gebruiker, ook al is de pagina verdwenen.

Mogelijke voorgaande toestanden:
verborgen (geen gebeurtenissen geactiveerd)
bevroren (geen gebeurtenissen geactiveerd)

Mogelijke volgende toestanden:
GEEN

Evenementen

Browsers versturen veel gebeurtenissen, maar slechts een klein deel daarvan signaleert een mogelijke wijziging in de levenscyclusstatus van een pagina. De volgende tabel geeft een overzicht van alle gebeurtenissen die betrekking hebben op de levenscyclus en de statussen waarnaar en waaruit ze kunnen overgaan.

Naam Details
focus

Een DOM-element heeft de focus gekregen.

Let op: een focus signaleert niet noodzakelijkerwijs een statuswijziging. Het signaleert alleen een statuswijziging als de pagina voorheen geen invoerfocus had.

Mogelijke voorgaande toestanden:
passief

Mogelijke huidige toestanden:
actief

blur

Een DOM-element is de focus kwijtgeraakt.

Let op: een blur -gebeurtenis signaleert niet noodzakelijkerwijs een statuswijziging. Het signaleert alleen een statuswijziging als de pagina niet langer de invoerfocus heeft (d.w.z. dat de pagina niet zomaar de focus van het ene element naar het andere heeft verplaatst).

Mogelijke voorgaande toestanden:
actief

Mogelijke huidige toestanden:
passief

visibilitychange

De waarde van visibilityState in het document is gewijzigd. Dit kan gebeuren wanneer een gebruiker naar een nieuwe pagina navigeert, van tabblad wisselt, een tabblad sluit, de browser minimaliseert of sluit, of schakelt tussen apps op mobiele besturingssystemen.

Mogelijke voorgaande toestanden:
passief
verborgen

Mogelijke huidige toestanden:
passief
verborgen

freeze *

De pagina is zojuist geblokkeerd. Eventuele geblokkeerde taken in de taakwachtrijen van de pagina worden niet gestart.

Mogelijke voorgaande toestanden:
verborgen

Mogelijke huidige toestanden:
bevroren

resume *

De browser heeft een vastgelopen pagina hervat.

Mogelijke voorgaande toestanden:
bevroren

Mogelijke huidige toestanden:
actief (indien gevolgd door de pageshow gebeurtenis)
passief (indien gevolgd door de pageshow gebeurtenis)
verborgen

pageshow

Er wordt naar een sessiegeschiedenisitem genavigeerd.

Dit kan een geheel nieuwe pagina zijn die wordt geladen of een pagina die uit de back-forwardcache is gehaald. Als de pagina uit de back-forwardcache is gehaald, is de persisted eigenschap van het evenement true , anders false .

Mogelijke voorgaande toestanden:
bevroren (een resume zou ook zijn geactiveerd)

Mogelijke huidige toestanden:
actief
passief
verborgen

pagehide

Er wordt een sessiegeschiedenisitem doorlopen.

Als de gebruiker naar een andere pagina navigeert en de browser de huidige pagina aan de back-forward cache kan toevoegen om later opnieuw te gebruiken, is de persisted eigenschap van de gebeurtenis true . Indien true , gaat de pagina naar de bevroren status, anders naar de beëindigde status.

Mogelijke voorgaande toestanden:
verborgen

Mogelijke huidige toestanden:
bevroren ( event.persisted is true, freeze gebeurtenis volgt)
beëindigd ( event.persisted is false, unload -event volgt)

beforeunload

Het venster, het document en de bijbehorende bronnen worden binnenkort verwijderd. Het document is nog steeds zichtbaar en de gebeurtenis kan op dit moment nog steeds worden geannuleerd.

Belangrijk: de beforeunload -gebeurtenis mag alleen worden gebruikt om de gebruiker te waarschuwen voor niet-opgeslagen wijzigingen. Zodra deze wijzigingen zijn opgeslagen, moet de gebeurtenis worden verwijderd. Deze mag nooit onvoorwaardelijk aan de pagina worden toegevoegd, aangezien dit in sommige gevallen de prestaties kan verslechteren. Zie de sectie over verouderde API's voor meer informatie.

Mogelijke voorgaande toestanden:
verborgen

Mogelijke huidige toestanden:
beëindigd

unload

De pagina wordt verwijderd.

Waarschuwing: het gebruik van de unload -gebeurtenis wordt nooit aanbevolen, omdat deze onbetrouwbaar is en in sommige gevallen de prestaties negatief kan beïnvloeden. Zie de sectie over verouderde API's voor meer informatie.

Mogelijke voorgaande toestanden:
verborgen

Mogelijke huidige toestanden:
beëindigd

* Geeft een nieuwe gebeurtenis aan die is gedefinieerd door de Page Lifecycle API

Nieuwe functies toegevoegd in Chrome 68

De vorige grafiek toont twee statussen die door het systeem worden geïnitieerd in plaats van door de gebruiker: bevroren en verwijderd . Zoals eerder vermeld, blokkeren en verwijderen browsers tegenwoordig al af en toe verborgen tabbladen (naar eigen goeddunken), maar ontwikkelaars hebben geen manier om te weten wanneer dit gebeurt.

In Chrome 68 kunnen ontwikkelaars nu zien wanneer een verborgen tabblad wordt vastgezet en weer wordt vrijgemaakt door te luisteren naar de freeze en resume in document .

document.addEventListener('freeze', (event) => {
  // The page is now frozen.
});

document.addEventListener('resume', (event) => {
  // The page has been unfrozen.
});

Vanaf Chrome 68 bevat het document nu de eigenschap wasDiscarded op desktop-Chrome ( Android-ondersteuning wordt in dit probleem bijgehouden ). Om te bepalen of een pagina is verwijderd terwijl deze zich in een verborgen tabblad bevond, kunt u de waarde van deze eigenschap bekijken tijdens het laden van de pagina (let op: verwijderde pagina's moeten opnieuw worden geladen om ze opnieuw te kunnen gebruiken).

if (document.wasDiscarded) {
  // Page was previously discarded by the browser while in a hidden tab.
}

Voor advies over wat u moet doen bij freeze en resume en hoe u zich kunt voorbereiden op het verwijderen van pagina's, raadpleegt u de aanbevelingen voor ontwikkelaars voor elke status .

De volgende secties bieden een overzicht van hoe deze nieuwe functies passen bij de bestaande statussen en gebeurtenissen van het webplatform.

Hoe u de levenscyclusstatus van pagina's in code kunt observeren

In de actieve , passieve en verborgen status is het mogelijk om JavaScript-code uit te voeren die de huidige levenscyclusstatus van de pagina bepaalt op basis van bestaande API's van het webplatform.

const getState = () => {
  if (document.visibilityState === 'hidden') {
    return 'hidden';
  }
  if (document.hasFocus()) {
    return 'active';
  }
  return 'passive';
};

De bevroren en beëindigde toestanden kunnen daarentegen alleen worden gedetecteerd in hun respectievelijke gebeurtenisluisteraar ( freeze en pagehide ), aangezien de toestand verandert.

Hoe toestandsveranderingen te observeren

Voortbouwend op de eerder gedefinieerde getState() functie kunt u alle wijzigingen in de levenscyclus van pagina's bekijken met de volgende code.

// Stores the initial state using the `getState()` function (defined above).
let state = getState();

// Accepts a next state and, if there's been a state change, logs the
// change to the console. It also updates the `state` value defined above.
const logStateChange = (nextState) => {
  const prevState = state;
  if (nextState !== prevState) {
    console.log(`State change: ${prevState} >>> ${nextState}`);
    state = nextState;
  }
};

// Options used for all event listeners.
const opts = {capture: true};

// These lifecycle events can all use the same listener to observe state
// changes (they call the `getState()` function to determine the next state).
['pageshow', 'focus', 'blur', 'visibilitychange', 'resume'].forEach((type) => {
  window.addEventListener(type, () => logStateChange(getState()), opts);
});

// The next two listeners, on the other hand, can determine the next
// state from the event itself.
window.addEventListener('freeze', () => {
  // In the freeze event, the next state is always frozen.
  logStateChange('frozen');
}, opts);

window.addEventListener('pagehide', (event) => {
  // If the event's persisted property is `true` the page is about
  // to enter the back/forward cache, which is also in the frozen state.
  // If the event's persisted property is not `true` the page is
  // about to be unloaded.
  logStateChange(event.persisted ? 'frozen' : 'terminated');
}, opts);

Deze code doet drie dingen:

  • Stelt de begintoestand in met behulp van de getState() functie.
  • Definieert een functie die een volgende status accepteert en, als er een verandering is, de statuswijzigingen naar de console registreert.
  • Voegt vastleggende gebeurtenisluisteraars toe voor alle noodzakelijke levenscyclusgebeurtenissen, die op hun beurt logStateChange() aanroepen en de volgende status doorgeven.

Een ding om op te merken aan de code is dat alle event listeners aan window worden toegevoegd en allemaal {capture: true} passeren. Daar zijn een paar redenen voor:

  • Niet alle gebeurtenissen in de levenscyclus van een pagina hebben hetzelfde doel. pagehide en pageshow worden geactiveerd op window ; visibilitychange , freeze en resume worden geactiveerd op document ; focus en blur worden geactiveerd op de bijbehorende DOM-elementen.
  • De meeste van deze gebeurtenissen bubbelen niet, wat betekent dat het onmogelijk is om niet-vastleggende gebeurtenisluisteraars toe te voegen aan een gemeenschappelijk voorouderelement en ze allemaal te observeren.
  • De capture-fase wordt uitgevoerd vóór de target- of bubble-fasen. Door listeners toe te voegen aan deze fase, zorg je ervoor dat ze worden uitgevoerd voordat andere code ze kan annuleren.

Aanbevelingen van ontwikkelaars voor elke staat

Als ontwikkelaar is het belangrijk om de levenscyclusstatussen van pagina's te begrijpen en te weten hoe je deze in code kunt observeren. Het soort werk dat je wel en niet moet doen, hangt namelijk grotendeels af van de status van je pagina.

Het is bijvoorbeeld duidelijk niet zinvol om een ​​tijdelijke melding aan de gebruiker te tonen als de pagina verborgen is. Hoewel dit voorbeeld vrij voor de hand liggend is, zijn er andere aanbevelingen die minder voor de hand liggen en die het waard zijn om te noemen.

Staat Aanbevelingen van ontwikkelaars
Active

De actieve status is het meest kritieke moment voor de gebruiker en dus het belangrijkste moment om uw pagina te laten reageren op gebruikersinvoer .

Alle niet-UI-werkzaamheden die de hoofdthread kunnen blokkeren, moeten een lagere prioriteit krijgen en naar inactieve periodes worden verplaatst of naar een webworker worden verplaatst .

Passive

In de passieve toestand heeft de gebruiker geen interactie met de pagina, maar kan hij deze nog steeds zien. Dit betekent dat UI-updates en animaties nog steeds vloeiend moeten zijn, maar het tijdstip waarop deze updates plaatsvinden is minder cruciaal.

Wanneer de pagina van actief naar passief verandert, is het een goed moment om de niet-opgeslagen toepassingsstatus te behouden.

Hidden

Wanneer de pagina van passief naar verborgen verandert, is het mogelijk dat de gebruiker er pas weer mee interacteert nadat de pagina opnieuw is geladen.

De overgang naar verborgen is vaak ook de laatste statuswijziging die door ontwikkelaars betrouwbaar kan worden waargenomen (dit geldt met name op mobiele apparaten, aangezien gebruikers tabbladen of de browser-app zelf kunnen sluiten. In die gevallen worden de gebeurtenissen beforeunload , pagehide en unload niet geactiveerd).

Dit betekent dat u de verborgen status moet beschouwen als het waarschijnlijke einde van de gebruikerssessie. Met andere woorden: bewaar alle niet-opgeslagen applicatiestatussen en verstuur alle niet-verzonden analysegegevens.

U moet ook stoppen met het uitvoeren van UI-updates (aangezien deze niet door de gebruiker worden gezien) en u moet alle taken stoppen die een gebruiker niet op de achtergrond wil laten uitvoeren.

Frozen

In de bevroren toestand worden bevriesbare taken in de taakwachtrij opgeschort totdat de pagina wordt ontdooid. Dit gebeurt mogelijk nooit (bijvoorbeeld als de pagina wordt verwijderd).

Dit betekent dat wanneer de pagina verandert van verborgen naar bevroren, het essentieel is om alle timers te stoppen of alle verbindingen te verbreken die, als ze bevroren zouden worden, andere geopende tabbladen in dezelfde oorsprong zouden kunnen beïnvloeden of de mogelijkheid van de browser om de pagina in de back-forward cache te plaatsen, zouden kunnen beïnvloeden.

Het is vooral belangrijk dat u:

Ook moet u eventuele dynamische weergavestatussen (bijvoorbeeld de scrollpositie in een oneindige lijstweergave) opslaan in sessionStorage (of IndexedDB via commit() ) als u de pagina wilt herstellen als deze wordt verwijderd en later opnieuw wordt geladen.

Als de pagina van bevroren naar verborgen overgaat, kunt u alle gesloten verbindingen opnieuw openen of de polling opnieuw starten die u hebt gestopt toen de pagina voor het eerst werd bevroren.

Terminated

Normaal gesproken hoeft u geen actie te ondernemen wanneer een pagina overgaat naar de beëindigde status.

Omdat pagina's die als gevolg van een gebruikersactie worden verwijderd, altijd de verborgen status doorlopen voordat ze in de beëindigde status terechtkomen, moet de logica voor het beëindigen van de sessie (bijvoorbeeld het behouden van de toepassingsstatus en het rapporteren aan Analytics) worden uitgevoerd in de verborgen status.

Bovendien (zoals vermeld in de aanbevelingen voor de verborgen status ) is het voor ontwikkelaars erg belangrijk om te beseffen dat de overgang naar de beëindigde status in veel gevallen niet betrouwbaar kan worden gedetecteerd (met name op mobiele apparaten). Ontwikkelaars die afhankelijk zijn van beëindigingsgebeurtenissen (bijv. beforeunload , pagehide en unload ) verliezen dus waarschijnlijk gegevens.

Discarded

De verwijderde status is niet zichtbaar voor ontwikkelaars op het moment dat een pagina wordt verwijderd. Dit komt doordat pagina's doorgaans worden verwijderd onder beperkte resourcebeperkingen, en het ontdooien van een pagina om scripts te laten draaien als reactie op een verwijderingsgebeurtenis in de meeste gevallen simpelweg niet mogelijk is.

U moet er daarom rekening mee houden dat er bij de wijziging van verborgen naar bevroren een verwijdering kan plaatsvinden. Vervolgens kunt u bij het herstellen van een verwijderde pagina tijdens het laden van de pagina reageren door document.wasDiscarded aan te vinken.

Omdat de betrouwbaarheid en volgorde van levenscyclusgebeurtenissen niet consistent in alle browsers is geïmplementeerd, kunt u het advies in de tabel het gemakkelijkst volgen door PageLifecycle.js te gebruiken.

Verouderde levenscyclus-API's die u moet vermijden

De volgende gebeurtenissen moeten zoveel mogelijk worden vermeden.

Het ontlaadevenement

Veel ontwikkelaars behandelen de unload -gebeurtenis als een gegarandeerde callback en gebruiken deze als een einde-sessiesignaal om de status op te slaan en analysegegevens te verzenden. Dit is echter uiterst onbetrouwbaar , vooral op mobiele apparaten! De unload -gebeurtenis wordt in veel typische unload-situaties niet geactiveerd, zoals bij het sluiten van een tabblad vanuit de tabbladwisselaar op mobiele apparaten of het sluiten van de browser-app vanuit de appwisselaar.

Om deze reden is het altijd beter om te vertrouwen op de visibilitychange -gebeurtenis om te bepalen wanneer een sessie eindigt, en de verborgen status te beschouwen als het laatste betrouwbare tijdstip om app- en gebruikersgegevens op te slaan .

Bovendien kan de aanwezigheid van een geregistreerde unload -gebeurtenisafhandeling (via onunload of addEventListener() ) ervoor zorgen dat browsers geen pagina's in de back-forwardcache kunnen plaatsen voor snellere back-up en back-up.

In alle moderne browsers wordt aanbevolen om altijd de pagehide -gebeurtenis te gebruiken om mogelijke pagina-unloads (ook wel de beëindigde status genoemd) te detecteren in plaats van de unload -gebeurtenis. Als u Internet Explorer versie 10 en lager wilt ondersteunen, moet u de pagehide -gebeurtenis detecteren en unload alleen gebruiken als de browser pagehide niet ondersteunt:

const terminationEvent = 'onpagehide' in self ? 'pagehide' : 'unload';

window.addEventListener(terminationEvent, (event) => {
  // Note: if the browser is able to cache the page, `event.persisted`
  // is `true`, and the state is frozen rather than terminated.
});

Het beforeunload-evenement

De beforeunload -gebeurtenis heeft een soortgelijk probleem als de unload -gebeurtenis: de aanwezigheid van een beforeunload -gebeurtenis kon er in het verleden voor zorgen dat pagina's niet in aanmerking kwamen voor back-forwardcache . Moderne browsers hebben deze beperking niet. Sommige browsers activeren echter uit voorzorg de beforeunload -gebeurtenis niet wanneer een pagina in de back-forwardcache wordt geplaatst, wat betekent dat de gebeurtenis niet betrouwbaar is als einde-sessiesignaal. Bovendien vereisen sommige browsers (waaronder Chrome ) gebruikersinteractie op de pagina voordat de beforeunload -gebeurtenis wordt geactiveerd, wat de betrouwbaarheid ervan verder beïnvloedt.

Een verschil tussen beforeunload en unload is dat beforeunload legitiem kan worden gebruikt. Bijvoorbeeld wanneer je de gebruiker wilt waarschuwen dat er niet-opgeslagen wijzigingen zijn die verloren gaan als hij/zij de pagina blijft unloaden.

Omdat er geldige redenen zijn om beforeunload te gebruiken, wordt aanbevolen om beforeunload listeners alleen toe te voegen wanneer een gebruiker niet-opgeslagen wijzigingen heeft. Verwijder deze wijzigingen vervolgens direct nadat ze zijn opgeslagen.

Met andere woorden, doe dit niet (het voegt namelijk onvoorwaardelijk een beforeunload listener toe):

addEventListener('beforeunload', (event) => {
  // A function that returns `true` if the page has unsaved changes.
  if (pageHasUnsavedChanges()) {
    event.preventDefault();

    // Legacy support for older browsers.
    event.returnValue = true;
  }
});

Doe in plaats daarvan het volgende (omdat de beforeunload -listener alleen wordt toegevoegd als dat nodig is, en wordt verwijderd als dat niet het geval is):

const beforeUnloadListener = (event) => {
  event.preventDefault();

  // Legacy support for older browsers.
  event.returnValue = true;
};

// A function that adds a `beforeunload` listener if there are unsaved changes.
onPageHasUnsavedChanges(() => {
  addEventListener('beforeunload', beforeUnloadListener);
});

// A function that removes the `beforeunload` listener when the page's unsaved
// changes are resolved.
onAllChangesSaved(() => {
  removeEventListener('beforeunload', beforeUnloadListener);
});

Veelgestelde vragen

Waarom is er geen "laden"-status?

De Page Lifecycle API definieert statussen als afzonderlijk en wederzijds exclusief. Omdat een pagina zowel in de actieve, passieve als verborgen status kan worden geladen, en van status kan veranderen – of zelfs kan worden beëindigd – voordat het laden is voltooid, is een aparte laadstatus binnen dit paradigma niet zinvol.

Mijn pagina voert belangrijk werk uit terwijl deze verborgen is. Hoe kan ik voorkomen dat deze wordt bevroren of verwijderd?

Er zijn talloze legitieme redenen waarom webpagina's niet bevroren zouden moeten zijn terwijl ze in de verborgen modus draaien. Het meest voor de hand liggende voorbeeld is een app die muziek afspeelt.

Er zijn ook situaties waarin het voor Chrome riskant zou zijn om een ​​pagina te negeren, bijvoorbeeld als de pagina een formulier bevat met niet-verzonden gebruikersinvoer of als er een beforeunload handler is die waarschuwt wanneer de pagina wordt verwijderd.

Chrome gaat voorlopig voorzichtig om met het verwijderen van pagina's en doet dit alleen als het er zeker van is dat het geen gevolgen heeft voor gebruikers. Pagina's waarvan bijvoorbeeld is vastgesteld dat ze een van de volgende handelingen uitvoeren in de verborgen status, worden niet verwijderd, tenzij er sprake is van extreme resourcebeperkingen:

  • Audio afspelen
  • WebRTC gebruiken
  • De tabeltitel of favicon bijwerken
  • Waarschuwingen weergeven
  • Pushmeldingen verzenden

Voor de huidige lijst met functies die worden gebruikt om te bepalen of een tabblad veilig kan worden bevroren of verwijderd, zie: Heuristiek voor bevriezen en verwijderen in Chrome.

Wat is de back/forward cache?

De back/forward cache is een term die wordt gebruikt om de navigatie-optimalisatie te beschrijven die sommige browsers implementeren en waarmee de knoppen voor terug en vooruit sneller kunnen worden gebruikt.

Wanneer een gebruiker een pagina verlaat, bevriezen deze browsers een versie van die pagina, zodat deze snel kan worden hervat als de gebruiker terug navigeert met de knoppen Terug of Vooruit. Houd er rekening mee dat het toevoegen van een unload -gebeurtenishandler deze optimalisatie onmogelijk maakt .

In feite is dit bevriezen functioneel gezien hetzelfde als wat bevriezende browsers doen om CPU/batterij te sparen. Om die reden wordt het beschouwd als onderdeel van de bevroren levenscyclusstatus.

Als ik geen asynchrone API's kan uitvoeren in de bevroren of beëindigde status, hoe kan ik dan gegevens opslaan in IndexedDB?

In een bevroren of beëindigde status worden bevriesbare taken in de taakwachtrijen van een pagina opgeschort. Dit betekent dat asynchrone en callback-gebaseerde API's niet op betrouwbare wijze kunnen worden gebruikt.

Hoewel de meeste IndexedDB API's callback-gebaseerd zijn, biedt de commit() methode in de IDBTransaction interface een manier om het commitproces voor een actieve transactie te starten zonder te wachten op de verzending van gebeurtenissen uit openstaande verzoeken. Dit biedt een betrouwbare manier om gegevens op te slaan in een IndexedDB-database in een freeze of visibilitychange gebeurtenislistener, omdat de commit direct wordt uitgevoerd in plaats van in een aparte taak in de wachtrij te worden geplaatst.

Uw app testen in de bevroren en verwijderde toestand

Als u wilt testen hoe uw app zich gedraagt ​​in de bevroren of verwijderde staat, kunt u chrome://discards bezoeken om al uw geopende tabbladen te bevriezen of te verwijderen.

Chrome verwijdert gebruikersinterface
Chrome verwijdert gebruikersinterface

Hiermee kunt u ervoor zorgen dat uw pagina de freeze en resume en de document.wasDiscarded -vlag correct verwerkt wanneer pagina's opnieuw worden geladen na een verwijdering.

Samenvatting

Ontwikkelaars die de systeembronnen van de apparaten van hun gebruikers willen respecteren, moeten hun apps bouwen met de levenscyclusstatus van pagina's in gedachten. Het is cruciaal dat webpagina's geen overmatige systeembronnen verbruiken in situaties die de gebruiker niet zou verwachten.

Hoe meer ontwikkelaars de nieuwe Page Lifecycle API's implementeren, hoe veiliger browsers pagina's die niet worden gebruikt, kunnen blokkeren en verwijderen. Dit betekent dat browsers minder geheugen, CPU, batterij en netwerkbronnen verbruiken, wat een voordeel is voor gebruikers.