API Page Lifecycle

Navigateurs pris en charge

  • Chrome: 68.
  • Edge: 79.
  • Firefox: non compatible.
  • Safari: non compatible.

Les navigateurs modernes suspendent parfois des pages ou les abandonnent complètement lorsque les ressources système sont limitées. À l'avenir, les navigateurs souhaitent le faire de manière proactive afin de consommer moins d'énergie et de mémoire. L'API Page Lifecycle fournit des crochets de cycle de vie afin que vos pages puissent gérer ces interventions du navigateur de manière sécurisée sans affecter l'expérience utilisateur. Consultez l'API pour déterminer si vous devez implémenter ces fonctionnalités dans votre application.

Contexte

Le cycle de vie des applications est un moyen essentiel pour les systèmes d'exploitation modernes de gérer les ressources. Sur Android, iOS et les versions récentes de Windows, les applications peuvent être démarrées et arrêtées à tout moment par l'OS. Cela permet à ces plates-formes de simplifier et de réallouer les ressources là où elles sont le plus utiles à l'utilisateur.

Sur le Web, il n'y a historiquement pas de cycle de vie de ce type, et les applications peuvent être maintenues en vie indéfiniment. Lorsque de nombreuses pages Web sont exécutées, les ressources système critiques telles que la mémoire, le processeur, la batterie et le réseau peuvent être surabonnées, ce qui entraîne une mauvaise expérience utilisateur.

Bien que la plate-forme Web dispose depuis longtemps d'événements liés aux états de cycle de vie (comme load, unload et visibilitychange), ces événements ne permettent aux développeurs que de répondre aux modifications d'état de cycle de vie déclenchées par l'utilisateur. Pour que le Web fonctionne de manière fiable sur les appareils à faible consommation d'énergie (et soit plus respectueux des ressources en général sur toutes les plates-formes), les navigateurs doivent pouvoir récupérer et réallouer de manière proactive les ressources système.

En fait, les navigateurs d'aujourd'hui prennent déjà des mesures actives pour économiser des ressources pour les pages dans les onglets en arrière-plan, et de nombreux navigateurs (en particulier Chrome) aimeraient en faire beaucoup plus pour réduire leur empreinte globale sur les ressources.

Le problème est que les développeurs n'ont aucun moyen de se préparer à ces types d'interventions déclenchées par le système, ni même de savoir qu'elles se produisent. Cela signifie que les navigateurs doivent être conservateurs, sinon ils risquent de casser les pages Web.

L'API Page Lifecycle tente de résoudre ce problème en:

  • Introduction et normalisation du concept d'états de cycle de vie sur le Web.
  • Définition de nouveaux états déclenchés par le système qui permettent aux navigateurs de limiter les ressources pouvant être consommées par les onglets masqués ou inactifs.
  • Créer des API et des événements qui permettent aux développeurs Web de répondre aux transitions vers et depuis ces nouveaux états déclenchés par le système.

Cette solution offre aux développeurs Web la prévisibilité dont ils ont besoin pour créer des applications résilientes aux interventions système. Elle permet aux navigateurs d'optimiser plus agressivement les ressources système, ce qui profite à tous les utilisateurs du Web.

Le reste de cet article présente les nouvelles fonctionnalités du cycle de vie des pages et explique comment elles se rapportent à tous les états et événements existants de la plate-forme Web. Il fournit également des recommandations et des bonnes pratiques concernant les types de travail que les développeurs doivent (et ne doivent pas) effectuer à chaque étape.

Présentation des états et des événements du cycle de vie des pages

Tous les états du cycle de vie des pages sont distincts et mutuellement exclusifs, ce qui signifie qu'une page ne peut être dans qu'un seul état à la fois. La plupart des modifications apportées à l'état du cycle de vie d'une page sont généralement observables via des événements DOM (voir les recommandations pour les développeurs pour chaque état pour les exceptions).

Le moyen le plus simple d'expliquer les états du cycle de vie de la page, ainsi que les événements qui signalent les transitions entre eux, est de créer un diagramme:

Représentation visuelle du flux d'état et d'événements décrit dans tout ce document.
État et flux d'événements de l'API Page Lifecycle.

États

Le tableau suivant explique en détail chaque état. Il liste également les états possibles qui peuvent se produire avant et après, ainsi que les événements que les développeurs peuvent utiliser pour observer les modifications.

État Description
Actif

Une page est dans l'état actif si elle est visible et que le focus de saisie est défini dessus.

États précédents possibles:
passif (via l'événement focus)
figé (via l'événement resume, puis l'événement pageshow)

Étapes suivantes possibles:
passif (via l'événement blur)

Passif

Une page est à l'état passif si elle est visible et qu'elle n'est pas sélectionnée.

États précédents possibles:
actif (via l'événement blur)
masqué (via l'événement visibilitychange)
figé (via l'événement resume, puis l'événement pageshow)

États suivants possibles:
actif (via l'événement focus)
masqué (via l'événement visibilitychange)

Hidden

Une page est dans l'état masquée si elle n'est pas visible (et qu'elle n'a pas été figée, supprimée ou arrêtée).

États précédents possibles:
passif (via l'événement visibilitychange)
figé (via l'événement resume, puis l'événement pageshow)

Étapes suivantes possibles:
passif (via l'événement visibilitychange)
figé (via l'événement freeze)
abandonné (aucun événement déclenché)
terminé (aucun événement déclenché)

Figé

Dans l'état figé, le navigateur suspend l'exécution des tâches figables dans les files d'attente de tâches de la page jusqu'à ce qu'elle soit dégelée. Cela signifie que les minuteurs JavaScript et les rappels de récupération ne s'exécutent pas. Les tâches déjà en cours d'exécution peuvent se terminer (en particulier le rappel freeze), mais elles peuvent être limitées dans ce qu'elles peuvent faire et dans la durée de leur exécution.

Les navigateurs figent les pages pour préserver l'utilisation du processeur, de la batterie et des données. Ils le font également pour accélérer les navigations avant/arrière, ce qui évite de recharger complètement la page.

États précédents possibles:
masqué (via l'événement freeze)

Étapes suivantes possibles:
actif (via l'événement resume, puis l'événement pageshow)
passif (via l'événement resume, puis l'événement pageshow)
masqué (via l'événement resume)
abandonné (aucun événement déclenché)

Résilié

Une page est dans l'état terminé une fois qu'elle a commencé à être désinstallée et effacée de la mémoire par le navigateur. Aucune nouvelle tâche ne peut démarrer dans cet état, et les tâches en cours peuvent être arrêtées si elles s'exécutent trop longtemps.

États précédents possibles:
masqué (via l'événement pagehide)

Étapes suivantes possibles:
NONE

Supprimées

Une page est dans l'état supprimée lorsqu'elle est déchargée par le navigateur afin de conserver des ressources. Aucune tâche, aucun rappel d'événement ni aucun code JavaScript ne peut s'exécuter dans cet état, car les suppressions se produisent généralement en cas de contraintes de ressources, où il est impossible de démarrer de nouveaux processus.

Dans l'état abandonné, l'onglet lui-même (y compris le titre et l'icône de l'onglet) est généralement visible par l'utilisateur, même si la page a disparu.

États précédents possibles:
masqué (aucun événement déclenché)
figé (aucun événement déclenché)

Étapes suivantes possibles:
NONE

Événements

Les navigateurs distribuent de nombreux événements, mais seule une petite partie d'entre eux signalent un éventuel changement d'état du cycle de vie de la page. Le tableau suivant décrit tous les événements liés au cycle de vie et indique les états vers lesquels et à partir desquels ils peuvent effectuer une transition.

Nom Détails
focus

Un élément DOM a reçu la sélection.

Remarque:Un événement focus ne signale pas nécessairement un changement d'état. Il ne signale un changement d'état que si la page n'était pas précédemment sélectionnée.

États précédents possibles:
passive

États actuels possibles:
active

blur

Un élément DOM a perdu la sélection.

Remarque:Un événement blur ne signale pas nécessairement un changement d'état. Il ne signale un changement d'état que si la page n'est plus sélectionnée (c'est-à-dire que la page n'a pas simplement changé de focus d'un élément à un autre).

États précédents possibles:
active

États actuels possibles:
passif

visibilitychange

La valeur visibilityState du document a changé. Cela peut se produire lorsqu'un utilisateur accède à une nouvelle page, change d'onglet, ferme un onglet, réduit ou ferme le navigateur, ou change d'application sur des systèmes d'exploitation mobiles.

États précédents possibles:
passif
masqué

États actuels possibles:
passif
caché

freeze *

La page vient d'être figée. Aucune tâche figable dans les files d'attente de tâches de la page ne sera démarrée.

États précédents possibles:
masqué

États actuels possibles:
frozen

resume *

Le navigateur a repris une page figée.

États précédents possibles:
figé

États actuels possibles:
actif (si suivi de l'événement pageshow)
passif (si suivi de l'événement pageshow)
masqué

pageshow

Une entrée de l'historique des sessions est parcourue.

Il peut s'agir d'un chargement de page entièrement nouveau ou d'une page extraite du cache "Précédent/Suivant". Si la page a été extraite du cache avant/arrière, la propriété persisted de l'événement est true, sinon elle est false.

États précédents possibles:
gelé (un événement resume aurait également été déclenché)

États actuels possibles:
actif
passif
masqué

pagehide

Une entrée de l'historique des sessions est parcourue.

Si l'utilisateur accède à une autre page et que le navigateur peut ajouter la page actuelle au cache avant/arrière pour la réutiliser ultérieurement, la propriété persisted de l'événement est true. Lorsque true, la page passe à l'état gelé, sinon elle passe à l'état terminé.

États précédents possibles:
masqué

États actuels possibles:
gelé (event.persisted est vrai, l'événement freeze suit)
terminé (event.persisted est faux, l'événement unload suit)

beforeunload

La fenêtre, le document et ses ressources sont sur le point d'être désinstallés. À ce stade, le document est toujours visible et l'événement peut toujours être annulé.

Important:L'événement beforeunload ne doit être utilisé que pour alerter l'utilisateur des modifications non enregistrées. Une fois ces modifications enregistrées, l'événement doit être supprimé. Il ne doit jamais être ajouté inconditionnellement à la page, car cela peut nuire aux performances dans certains cas. Pour en savoir plus, consultez la section Anciennes API.

États précédents possibles:
masqué

États actuels possibles:
terminated

unload

La page est en cours de déchargement.

Avertissement:L'utilisation de l'événement unload n'est jamais recommandée, car il n'est pas fiable et peut nuire aux performances dans certains cas. Pour en savoir plus, consultez la section Anciennes API.

États précédents possibles:
masqué

États actuels possibles:
terminé

* Indique un nouvel événement défini par l'API Page Lifecycle

Nouvelles fonctionnalités ajoutées dans Chrome 68

Le graphique précédent montre deux états déclenchés par le système plutôt que par l'utilisateur: gelé et abandonné. Comme indiqué précédemment, les navigateurs actuels gèlent et suppriment parfois des onglets masqués (à leur discrétion), mais les développeurs n'ont aucun moyen de savoir quand cela se produit.

Dans Chrome 68, les développeurs peuvent désormais observer quand un onglet masqué est gelé et dégelé en écoutant les événements freeze et resume sur document.

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

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

À partir de Chrome 68, l'objet document inclut désormais une propriété wasDiscarded dans Chrome pour ordinateur (la prise en charge d'Android est en cours de suivi pour ce problème). Pour déterminer si une page a été supprimée dans un onglet masqué, vous pouvez inspecter la valeur de cette propriété au moment du chargement de la page (remarque : les pages supprimées doivent être actualisées pour être réutilisées).

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

Pour obtenir des conseils sur les actions importantes à effectuer dans les événements freeze et resume, ainsi que sur la gestion et la préparation des pages à supprimer, consultez les recommandations pour les développeurs pour chaque état.

Les sections suivantes offrent un aperçu de la façon dont ces nouvelles fonctionnalités s'intègrent aux états et événements existants de la plate-forme Web.

Observer les états du cycle de vie de la page dans le code

Dans les états actif, passif et caché, il est possible d'exécuter du code JavaScript qui détermine l'état actuel du cycle de vie de la page à partir des API de plate-forme Web existantes.

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

En revanche, les états frozen (gelé) et terminated (terminé) ne peuvent être détectés que dans leur écouteur d'événements respectif (freeze et pagehide) lorsque l'état change.

Observer les changements d'état

En s'appuyant sur la fonction getState() définie précédemment, vous pouvez observer tous les changements d'état de la page avec le code suivant.

// 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);

Ce code effectue trois opérations:

  • Définit l'état initial à l'aide de la fonction getState().
  • Définit une fonction qui accepte un état suivant et, en cas de modification, consigne les changements d'état dans la console.
  • Ajoute des écouteurs d'événements de capture pour tous les événements de cycle de vie nécessaires, qui à leur tour appellent logStateChange(), en transmettant l'état suivant.

Notez que tous les écouteurs d'événements sont ajoutés à window et qu'ils transmettent tous {capture: true}. Plusieurs raisons peuvent expliquer ce phénomène :

  • Tous les événements de cycle de vie de la page n'ont pas la même cible. pagehide et pageshow sont déclenchés sur window. visibilitychange, freeze et resume sont déclenchés sur document, et focus et blur sont déclenchés sur leurs éléments DOM respectifs.
  • La plupart de ces événements ne se propagent pas, ce qui signifie qu'il est impossible d'ajouter des écouteurs d'événements non capturants à un élément ancêtre commun et de les observer tous.
  • La phase de capture s'exécute avant les phases de cible ou de bulle. L'ajout d'écouteurs à cet endroit permet de s'assurer qu'ils s'exécutent avant qu'un autre code ne puisse les annuler.

Recommandations pour les développeurs pour chaque état

En tant que développeur, il est important de comprendre les états du cycle de vie de la page et de savoir les observer dans le code, car le type de travail que vous devez (et ne devez pas) effectuer dépend en grande partie de l'état de votre page.

Par exemple, il n'a pas de sens d'afficher une notification temporaire à l'utilisateur si la page est à l'état masqué. Bien que cet exemple soit assez évident, d'autres recommandations moins évidentes méritent d'être énumérées.

État Recommandations pour les développeurs
Active

L'état actif est le moment le plus critique pour l'utilisateur. C'est donc le moment le plus important pour que votre page soit attentive aux entrées utilisateur.

Toute tâche non liée à l'UI pouvant bloquer le thread principal doit être dépriorisée pour les périodes d'inactivité ou déléguée à un nœud de calcul Web.

Passive

Dans l'état passif, l'utilisateur n'interagit pas avec la page, mais il peut toujours la voir. Cela signifie que les mises à jour et les animations de l'interface utilisateur doivent toujours être fluides, mais le moment où ces mises à jour se produisent est moins critique.

Lorsque la page passe de l'état actif à l'état passif, il est temps de conserver l'état de l'application non enregistré.

Hidden

Lorsque la page passe de passive à masquée, il est possible que l'utilisateur ne l'interagisse plus jusqu'à ce qu'elle soit actualisée.

La transition vers l'état masqué est également souvent le dernier changement d'état observable de manière fiable par les développeurs (c'est particulièrement vrai sur mobile, car les utilisateurs peuvent fermer des onglets ou l'application de navigateur elle-même, et les événements beforeunload, pagehide et unload ne sont pas déclenchés dans ces cas).

Par conséquent, vous devez considérer l'état masqué comme la fin probable de la session de l'utilisateur. En d'autres termes, conservez tout état d'application non enregistré et envoyez toutes les données analytiques non envoyées.

Vous devez également arrêter de mettre à jour l'UI (car elle ne sera pas visible par l'utilisateur) et arrêter toutes les tâches qu'un utilisateur ne souhaite pas exécuter en arrière-plan.

Frozen

À l'état figé, les tâches figables dans les files d'attente de tâches sont suspendues jusqu'à ce que la page soit dégelée, ce qui peut ne jamais se produire (par exemple, si la page est supprimée).

Par conséquent, lorsque la page passe de l'état masquée à l'état figée, il est essentiel d'arrêter tous les minuteurs ou de supprimer toutes les connexions qui, si elles sont figées, pourraient affecter d'autres onglets ouverts de la même origine ou la capacité du navigateur à placer la page dans le cache avant/arrière.

En particulier, vous devez:

Vous devez également conserver tout état de vue dynamique (par exemple, la position de défilement dans une vue de liste infinie) dans sessionStorage (ou IndexedDB via commit()) que vous souhaitez restaurer si la page est supprimée et réactualisée plus tard.

Si la page passe de l'état figé à l'état masqué, vous pouvez rouvrir les connexions fermées ou redémarrer les requêtes d'interrogation que vous avez arrêtées lorsque la page a été figée initialement.

Terminated

En général, aucune action n'est requise de votre part lorsqu'une page passe à l'état terminé.

Étant donné que les pages qui sont désinstallées en raison d'une action de l'utilisateur passent toujours par l'état masqué avant d'atteindre l'état terminé, c'est à l'état masqué que la logique de fin de session (par exemple, la persistance de l'état de l'application et les rapports aux outils d'analyse) doit être effectuée.

De plus (comme indiqué dans les recommandations pour l'état masqué), il est très important que les développeurs sachent que la transition vers l'état terminé ne peut pas être détectée de manière fiable dans de nombreux cas (en particulier sur mobile). Par conséquent, les développeurs qui dépendent des événements de fin (par exemple, beforeunload, pagehide et unload) risquent de perdre des données.

Discarded

L'état supprimé n'est pas visible par les développeurs au moment où une page est supprimée. En effet, les pages sont généralement supprimées en raison de contraintes de ressources. Dans la plupart des cas, il est tout simplement impossible de dégeler une page juste pour permettre l'exécution du script en réponse à un événement de suppression.

Par conséquent, vous devez vous préparer à la possibilité d'une suppression lors du passage de masqué à figé, puis vous pouvez réagir à la restauration d'une page supprimée au moment du chargement de la page en vérifiant document.wasDiscarded.

Encore une fois, étant donné que la fiabilité et l'ordre des événements de cycle de vie ne sont pas implémentés de manière cohérente dans tous les navigateurs, le moyen le plus simple de suivre les conseils du tableau consiste à utiliser PageLifecycle.js.

API de cycle de vie obsolètes à éviter

Dans la mesure du possible, les événements suivants doivent être évités.

Événement de déchargement

De nombreux développeurs traitent l'événement unload comme un rappel garanti et l'utilisent comme signal de fin de session pour enregistrer l'état et envoyer des données d'analyse. Toutefois, cette approche est extrêmement peu fiable, en particulier sur mobile. L'événement unload ne se déclenche pas dans de nombreuses situations d'arrêt typiques, y compris lorsque vous fermez un onglet à partir du sélecteur d'onglets sur mobile ou que vous fermez l'application de navigateur à partir du sélecteur d'applications.

Pour cette raison, il est toujours préférable de s'appuyer sur l'événement visibilitychange pour déterminer quand une session se termine et de considérer l'état masqué comme le dernier moment fiable pour enregistrer les données de l'application et de l'utilisateur.

De plus, la simple présence d'un gestionnaire d'événements unload enregistré (via onunload ou addEventListener()) peut empêcher les navigateurs de placer des pages dans le cache avant/arrière pour un chargement plus rapide des pages précédentes et suivantes.

Dans tous les navigateurs modernes, nous vous recommandons de toujours utiliser l'événement pagehide pour détecter les déchargements de page possibles (également appelés état terminé) plutôt que l'événement unload. Si vous devez prendre en charge les versions 10 et antérieures d'Internet Explorer, vous devez détecter l'événement pagehide et n'utiliser unload que si le navigateur n'est pas compatible avec pagehide:

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.
});

Événement beforeunload

L'événement beforeunload présente un problème similaire à celui de l'événement unload, en ce sens que, historiquement, la présence d'un événement beforeunload pouvait empêcher les pages d'être éligibles au cache avant/arrière. Les navigateurs modernes ne sont pas soumis à cette restriction. Toutefois, par mesure de précaution, certains navigateurs ne déclenchent pas l'événement beforeunload lorsqu'ils tentent de placer une page dans le cache "Retour/Avance", ce qui signifie que l'événement n'est pas fiable en tant que signal de fin de session. De plus, certains navigateurs (y compris Chrome) nécessitent une interaction de l'utilisateur sur la page avant de permettre le déclenchement de l'événement beforeunload, ce qui affecte encore plus sa fiabilité.

Une différence entre beforeunload et unload est qu'il existe des utilisations légitimes de beforeunload. Par exemple, lorsque vous souhaitez avertir l'utilisateur qu'il a des modifications non enregistrées qu'il perdra s'il continue de vider la page.

Étant donné qu'il existe des raisons valables d'utiliser beforeunload, nous vous recommandons d'ajouter uniquement des écouteurs beforeunload lorsqu'un utilisateur a des modifications non enregistrées, puis de les supprimer immédiatement après leur enregistrement.

En d'autres termes, ne faites pas cela (car cela ajoute un écouteur beforeunload sans condition):

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

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

À la place, procédez comme suit (puisque l'écouteur beforeunload n'est ajouté que lorsqu'il est nécessaire et supprimé lorsqu'il ne l'est pas):

const beforeUnloadListener = (event) => {
  event.preventDefault();
  
  // Legacy support for older browsers.
  return (event.returnValue = true);
};

// A function that invokes a callback when the page has unsaved changes.
onPageHasUnsavedChanges(() => {
  addEventListener('beforeunload', beforeUnloadListener);
});

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

Questions fréquentes

Pourquoi n'y a-t-il pas d'état "chargement" ?

L'API Page Lifecycle définit les états comme étant distincts et mutuellement exclusifs. Étant donné qu'une page peut être chargée dans les états actif, passif ou masqué, et qu'elle peut changer d'état (ou même être arrêtée) avant la fin du chargement, un état de chargement distinct n'a pas de sens dans ce paradigme.

Ma page effectue une tâche importante lorsqu'elle est masquée. Comment empêcher son blocage ou son abandon ?

De nombreuses raisons légitimes expliquent pourquoi les pages Web ne doivent pas être figées lorsqu'elles s'exécutent dans l'état masqué. L'exemple le plus évident est une application qui diffuse de la musique.

Il existe également des situations où il serait risqué pour Chrome de supprimer une page, par exemple si elle contient un formulaire avec une entrée utilisateur non envoyée ou si elle comporte un gestionnaire beforeunload qui émet un avertissement lorsque la page est en cours de déchargement.

Pour le moment, Chrome sera conservateur lorsqu'il abandonnera des pages et ne le fera que lorsqu'il sera sûr que cela n'affectera pas les utilisateurs. Par exemple, les pages qui ont été observées en train d'effectuer l'une des opérations suivantes lorsqu'elles sont dans l'état masqué ne seront pas supprimées, sauf en cas de contraintes de ressources extrêmes:

  • Lecture d'un contenu audio
  • Utiliser WebRTC
  • Modifier le titre ou la favicon de la table
  • Afficher les alertes
  • Envoyer des notifications push

Pour connaître les fonctionnalités de liste actuelles utilisées pour déterminer si un onglet peut être gelé ou supprimé en toute sécurité, consultez la section Heuristiques de gel et de suppression dans Chrome.

Qu'est-ce que le cache amélioré ?

Le cache "Précédent/Suivant" est un terme utilisé pour décrire une optimisation de la navigation implémentée par certains navigateurs, qui accélère l'utilisation des boutons "Précédent" et "Suivant".

Lorsqu'un utilisateur quitte une page, ces navigateurs figent une version de cette page afin qu'elle puisse être rapidement reprise si l'utilisateur revient en arrière à l'aide des boutons "Précédent" ou "Avant". N'oubliez pas que l'ajout d'un gestionnaire d'événements unload empêche cette optimisation.

À tous égards, ce blocage est fonctionnellement identique à celui effectué par les navigateurs pour économiser le processeur/la batterie. C'est pourquoi il fait partie de l'état de cycle de vie gelé.

Si je ne peux pas exécuter d'API asynchrones dans les états "gelé" ou "terminé", comment enregistrer des données dans IndexedDB ?

Dans les états "gelé" et "terminé", les tâches pouvant être gelées dans les files d'attente de tâches d'une page sont suspendues, ce qui signifie que les API asynchrones et basées sur des rappels telles que IndexedDB ne peuvent pas être utilisées de manière fiable.

À l'avenir, nous allons ajouter une méthode commit() aux objets IDBTransaction, ce qui permettra aux développeurs d'effectuer des transactions en écriture seule qui ne nécessitent pas de rappels. En d'autres termes, si le développeur ne fait que saisir des données dans IndexedDB et n'effectue pas de transaction complexe consistant en des lectures et des écritures, la méthode commit() pourra se terminer avant que les files d'attente de tâches ne soient suspendues (en supposant que la base de données IndexedDB est déjà ouverte).

Toutefois, pour le code qui doit fonctionner dès aujourd'hui, les développeurs ont deux options:

  • Utilisez le stockage de session:le stockage de session est synchrone et persiste lors de l'abandon de la page.
  • Utilisez IndexedDB à partir de votre service worker:un service worker peut stocker des données dans IndexedDB une fois la page terminée ou supprimée. Dans l'écouteur d'événements freeze ou pagehide, vous pouvez envoyer des données à votre service worker via postMessage(). Le service worker peut ensuite s'occuper de l'enregistrement des données.

Tester votre application dans les états "congelé" et "abandonné"

Pour tester le comportement de votre application dans les états "congelé" et "supprimé", vous pouvez accéder à chrome://discards pour congeler ou supprimer l'un de vos onglets ouverts.

UI de suppression de Chrome
UI Chrome supprimée

Cela vous permet de vous assurer que votre page gère correctement les événements freeze et resume, ainsi que l'indicateur document.wasDiscarded lorsque les pages sont actualisées après un abandon.

Résumé

Les développeurs qui souhaitent respecter les ressources système des appareils de leurs utilisateurs doivent créer leurs applications en tenant compte des états de cycle de vie de la page. Il est essentiel que les pages Web ne consomment pas de ressources système excessives dans des situations auxquelles l'utilisateur ne s'attend pas.

Plus les développeurs commenceront à implémenter les nouvelles API de cycle de vie des pages, plus il sera sûr pour les navigateurs de geler et d'abandonner les pages qui ne sont pas utilisées. Cela signifie que les navigateurs consomment moins de mémoire, de processeur, de batterie et de ressources réseau, ce qui est un avantage pour les utilisateurs.