Regardez le processus de rendu du navigateur et l'optimisation des performances à partir de 7 questions d'entretien

Préface

À l'ère de l'Internet mobile, les utilisateurs ont des exigences de plus en plus élevées pour la vitesse d'ouverture des pages Web. Les recherches du département de l'expérience utilisateur de Baidu montrent que la relation entre le taux d'abandon de page et le temps d'ouverture de la page est illustrée dans la figure ci-dessous.

Insérez la description de l'image ici

Selon les résultats de recherche du département de l'expérience utilisateur de Baidu, le temps de chargement de la page auquel les utilisateurs ordinaires s'attendent et peuvent accepter est de 3 secondes. Si le temps de chargement de la page est trop lent, les utilisateurs perdront patience et choisiront de partir.

En tant que premier écran face à l'utilisateur, l'importance du premier écran va de soi. L'optimisation de l'expérience utilisateur est l'une des choses sur lesquelles nous devons nous concentrer dans le développement frontal.

Dans cet article, nous parlerons du processus de rendu du navigateur et de l'optimisation des performances à travers 8 questions d'entretien.

Prenons d'abord ces 8 questions pour comprendre le processus de rendu du navigateur, et nous donnerons des solutions plus tard ~

  • Pourquoi un seul thread Javascript?
    Style Gras

  • Pourquoi JS bloque-t-il le chargement de la page?

  • Le chargement css provoquera-t-il un blocage?

  • La différence entre DOMContentLoaded et load?

  • Qu'est-ce que CRP, à savoir Critical Rendering Path? Comment optimiser?

  • Quelle est la différence entre defer et async?

  • Vous parlez de redistribution et de redessiner du navigateur?

Processus et fil

Le processus et le fil sont les concepts de base du système d'exploitation.

进程是 CPU 资源分配的最小单位(是能拥有资源和独立运行的最小单位)。

线程是 CPU 调度的最小单位(是建立在进程基础上的一次程序运行单位)。

Les systèmes d'exploitation modernes peuvent exécuter plusieurs tâches en même temps, par exemple, vous pouvez écouter de la musique tout en surfant sur Internet avec un navigateur.

对于操作系统来说,一个任务就是一个进程,Par exemple, l'ouverture d'un navigateur démarre un processus de navigateur et l'ouverture d'un Word démarre un processus Word.

Certains processus font plus d'une chose à la fois, comme Word, qui peut effectuer la saisie, la vérification orthographique, l'impression et d'autres choses en même temps.在一个进程内部,要同时做多件事,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”称为线程。

Puisque chaque processus doit faire au moins une chose, un processus a au moins un thread. Le système alloue une mémoire indépendante à chaque processus, de sorte que le processus dispose de ses propres ressources indépendantes. Chaque thread du même processus partage l'espace mémoire du processus (y compris les segments de code, les ensembles de données, les tas, etc.).

Pour emprunter une métaphore vivante, un processus est comme une usine de production avec une limite, et un fil est comme un employé dans l'usine, qui peut faire ses propres choses ou coopérer les uns avec les autres pour faire la même chose.

Lorsque nous démarrons une application, l'ordinateur créera un processus, le système d'exploitation allouera une partie de la mémoire pour le processus, tout l'état de l'application sera stocké dans cette mémoire.

L'application peut également créer plusieurs threads pour aider le travail, ces threads peuvent partager les données dans cette partie de la mémoire. Si l'application est fermée, le processus sera interrompu et le système d'exploitation libèrera la mémoire associée.

Insérez la description de l'image ici

Architecture multi-processus du navigateur

Un bon programme est souvent divisé en plusieurs modules indépendants et coopérant entre eux, tout comme les navigateurs.

Prenons l'exemple de Chrome. Il se compose de plusieurs processus, chacun ayant ses propres responsabilités principales. Ils coopèrent entre eux pour compléter la fonction globale du navigateur.

Chaque processus contient plusieurs threads et plusieurs threads dans un processus fonctionneront également ensemble pour remplir les responsabilités du processus.

Chrome adopte une architecture multi-processus, et il existe un processus de navigateur sur la couche supérieure pour coordonner d'autres processus du navigateur.Insérez la description de l'image ici

avantage

Puisqu'une nouvelle page à onglet est ouverte par défaut et qu'un nouveau processus est créé, un plantage de page à onglet unique n'affectera pas l'ensemble du navigateur.

De même, le plantage des plug-ins tiers n'affectera pas l'ensemble du navigateur.

Le multi-processus peut tirer pleinement parti des avantages du processeur multicœur moderne.

Il est pratique d'utiliser le modèle sandbox pour isoler les processus tels que les plug-ins et améliorer la stabilité du navigateur.

Désavantage

Le système alloue de la mémoire, du processeur et d'autres ressources pour le processus nouvellement ouvert du navigateur, de sorte que la consommation de ressources de mémoire et de processeur sera plus grande.

Cependant, Chrome a fait du bon travail dans la libération de la mémoire. La mémoire de base peut être libérée rapidement pour que d'autres programmes puissent s'exécuter.

Les principaux processus et responsabilités du navigateur

Insérez la description de l'image ici

主进程Browser Process

Responsable de l'affichage et de l'interaction de l'interface du navigateur. Gestion de chaque page, création et destruction d'autres processus. Gestion des ressources réseau, téléchargement, etc.

第三方插件进程 Plugin Process

Chaque type de plug-in correspond à un processus et est créé uniquement lorsque le plug-in est utilisé.

GPU 进程 GPU Process

Il n'y en a qu'un au plus, utilisé pour le dessin 3D, etc.

渲染进程 Renderer Process

Il est appelé processus de rendu du navigateur ou noyau du navigateur, qui est multithread en interne. Principalement responsable du rendu des pages, de l'exécution des scripts, de la gestion des événements, etc. (Cet article se concentre sur l'analyse)

渲染进程 Renderer Process

Le processus de rendu du navigateur est multi-thread, voyons quels threads principaux il a:

Insérez la description de l'image ici

1 fil de rendu GUI

  • Responsable du rendu de l'interface du navigateur, de l'analyse HTML, CSS, de la construction de l'arborescence DOM et de l'arborescence RenderObject, de la mise en page et du dessin, etc.

  • Lorsque l'interface doit être repeinte ou redistribuée en raison d'une opération, le thread s'exécute.

  • Notez que le thread de rendu de l'interface graphique et le thread du moteur JS s'excluent mutuellement. Lorsque le moteur JS est exécuté, le thread de l'interface graphique sera suspendu (ce qui équivaut à être gelé) et la mise à jour de l'interface graphique sera enregistrée dans une file d'attente jusqu'à ce que le moteur JS soit inactif. .

Filetage moteur 2 JS

  • Le moteur Javascript, également connu sous le nom de noyau JS, est responsable du traitement des programmes de script Javascript. (Par exemple, moteur V8)
  • Le thread du moteur JS est responsable de l'analyse des scripts Javascript et de l'exécution des codes.
  • Le moteur JS attend l'arrivée des tâches dans la file d'attente des tâches, puis les traite. Il n'y a qu'un seul thread JS exécutant le programme JS dans une page Onglet (processus de rendu) à la fois.
  • Notez que le thread de rendu de l'interface graphique et le thread du moteur JS sont mutuellement exclusifs, donc si le temps d'exécution JS est trop long, le rendu de la page sera incohérent et bloquera le rendu de la page.

3 Thread de déclenchement d'événement

  • Appartient au navigateur au lieu du moteur JS, utilisé pour contrôler la boucle d'événements (naturellement, le moteur JS lui-même est trop occupé et oblige le navigateur à ouvrir un thread pour aider)
  • Lorsque le moteur JS exécute des blocs de code tels que setTimeOut (également à partir d'autres threads du noyau du navigateur, tels que des clics de souris, des requêtes asynchrones AJAX, etc.), la tâche correspondante sera ajoutée au thread d'événement
  • Lorsque l'événement correspondant remplit la condition de déclenchement et est déclenché, le thread ajoutera l'événement à la fin de la file d'attente à traiter et attendra que le moteur JS traite
  • Notez qu'en raison de la relation monothread de JS, les événements de ces files d'attente en attente doivent être mis en file d'attente pour traitement par le moteur JS (exécuté uniquement lorsque le moteur JS est inactif)

4. Filetage du déclencheur de synchronisation

  • Le thread où se trouvent les légendaires setInterval et setTimeout
  • Le compteur du minuteur du navigateur n'est pas compté par le moteur JavaScript (parce que le moteur JavaScript est monothread, s'il est dans un état de thread bloqué, cela affectera la précision de la synchronisation)
  • Par conséquent, un thread séparé est utilisé pour chronométrer et déclencher le chronométrage (une fois le chronométrage terminé, il est ajouté à la file d'attente d'événements et exécuté après que le moteur JS est inactif)
  • Notez que le W3C stipule dans la norme HTML qu'un intervalle de temps inférieur à 4 ms dans setTimeout est compté pour 4 ms.

5 Fil de requête http asynchrone

  • Une fois XMLHttpRequest connecté, une nouvelle demande de thread est ouverte via le navigateur.
  • Lorsqu'un changement d'état est détecté, si une fonction de rappel est définie, le thread asynchrone génère un événement de changement d'état et place ce rappel dans la file d'attente d'événements. Puis exécuté par le moteur JavaScript.

6 Supplément: web worker

Les travailleurs Web sont un moyen pour javascript d'autoriser le multithreading. C'est un autre fil de calcul. Voir le journal de Ruan Dashen pour plus de détails ;

Résumé: Le js que nous utilisons habituellement n'est qu'un fil dans le processus du navigateur. De nombreuses opérations asynchrones, la gestion des rappels d'événements, etc. doivent être traitées par des threads supplémentaires, puis le thread javascript est notifié sous la forme d'événements.

Processus de rendu du navigateur

Si vous voulez parler de ce qui se passe de l'entrée de l'url au chargement de la page, c'est sans fin ... Ici, nous ne parlons que du processus de rendu du navigateur.
Insérez la description de l'image ici

  • Analyser les fichiers HTML, créer l'arborescence DOM et le processus principal du navigateur est responsable du téléchargement des fichiers CSS

  • Le fichier CSS est téléchargé, le fichier CSS est analysé dans une structure de données en forme d'arbre, puis combiné avec l'arborescence DOM pour former une arborescence RenderObject

  • Disposer l'arborescence RenderObject (Layout / reflow), responsable du calcul de la taille et de la position des éléments dans l'arborescence RenderObject

  • Dessinez l'arbre RenderObject (peinture), dessinez les informations de pixel de la page

  • Le processus de navigateur principal transmet les couches par défaut et les couches composites au processus GPU, et le processus GPU compose chaque couche (composite), et affiche enfin la page

répondre

1.为什么 Javascript 要是单线程的 ?

Cela est dû à la mission du langage de script Javascript! JavaScript gère l'interaction de l'utilisateur dans la page et manipule l'arborescence DOM et l'arbre de style CSS pour présenter aux utilisateurs une expérience interactive dynamique et riche et un traitement interactif de la logique du serveur.

Si JavaScript est un moyen multi-thread de manipuler ces DOM d'interface utilisateur, il peut y avoir des conflits dans les opérations d'interface utilisateur.

Si Javascript est multi-thread, sous interaction multi-thread, le nœud DOM dans l'interface utilisateur peut devenir une ressource critique.

En supposant qu'il y ait deux threads exploitant un DOM en même temps, l'un est responsable de la modification et l'autre est responsable de la suppression, alors le navigateur doit décider comment appliquer le résultat de l'exécution du thread.

Bien entendu, nous pouvons résoudre les problèmes ci-dessus en verrouillant. Mais afin d'éviter la plus grande complexité causée par l'introduction de verrous, Javascript a choisi au début l'exécution monothread.

2. 为什么 JS 阻塞页面加载 ?

Puisque JavaScript peut manipuler le DOM, si vous modifiez ces attributs d'élément lors du rendu de l'interface (c'est-à-dire que le thread JavaScript et le thread d'interface utilisateur s'exécutent en même temps), les données d'élément obtenues avant et après le thread de rendu peuvent être incohérentes.

Par conséquent, afin d'éviter le rendu de résultats imprévisibles, les paramètres du navigateurGUI 渲染线程与 JavaScript 引擎为互斥的关系。

当 JavaScript 引擎执行时 GUI 线程会被挂起,GUI 更新会被保存在一个队列中等到引擎线程空闲时立即被执行。

De ce qui précède, nous pouvons déduire qu'en raison de la relation mutuellement exclusive entre le thread de rendu de l'interface graphique et le thread d'exécution JavaScript,

Lorsque le navigateur exécute le programme JavaScript, le thread de rendu GUI sera stocké dans une file d'attente et ne continuera pas tant que le programme JS ne sera pas exécuté.

Par conséquent, si le temps d'exécution JS est trop long, le rendu de la page sera incohérent, conduisant à l'impression de bloquer le rendu et le chargement de la page.

3. css 加载会造成阻塞吗 ?

À partir du processus de rendu du navigateur ci-dessus, nous pouvons voir:

L'analyse DOM et l'analyse CSS sont deux processus parallèles, donc CSS 加载不会阻塞 DOM 的解析.

Cependant, étant donné que l'arbre de rendu dépend de l'arbre DOM et de l'arbre CSSOM,

Il doit donc attendre que l'arborescence CSSOM soit construite, c'est-à-dire que la ressource CSS soit chargée (ou que la ressource CSS ne se charge pas) avant le rendu.

donc,CSS 加载会阻塞 Dom 的渲染。

Étant donné que JavaScript peut manipuler les styles DOM et CSS, si vous modifiez ces attributs d'élément lors du rendu de l'interface (c'est-à-dire que le thread JavaScript et le thread d'interface utilisateur s'exécutent en même temps), les données d'élément obtenues avant et après le thread de rendu peuvent être incohérentes.

Par conséquent, afin d'éviter le rendu de résultats imprévisibles, les paramètres du navigateur GUI 渲染线程与 JavaScript 引擎为互斥的关系。

Par conséquent, la feuille de style sera chargée et exécutée avant l'exécution des js suivants, donccss 会阻塞后面 js 的执行。

4 DOMContentLoaded 与 load 的区别 ?

  • Lorsque l'événement DOMContentLoaded est déclenché, seulement une fois l'analyse DOM terminée, les feuilles de style et les images ne sont pas incluses. Nous avons mentionné précédemment que le chargement CSS bloquera le rendu de Dom et l'exécution de js plus tard, et js bloquera l'analyse de
    Dom.Nous pouvons donc en conclure que lorsqu'il n'y a pas de script dans le document, le navigateur peut déclencher l'événement DOMContentLoaded après l'analyse du document. Si le document contient un script, le script bloquera l'analyse du document et le script doit être exécuté après la construction du CSSOM. Dans tous les cas, le déclenchement de DOMContentLoaded n'a pas besoin d'attendre que les images et autres ressources soient chargées.

  • Lorsque l'événement onload est déclenché, tous les DOM, feuilles de style, scripts, images et autres ressources de la page ont été chargés.

  • DOMContentLoaded -> charger。

5. 什么是 CRP,即关键渲染路径(Critical Rendering Path)? 如何优化 ?

Le chemin de rendu critique est une série d'étapes que le navigateur doit suivre pour convertir HTML CSS JavaScript en contenu pixel rendu à l'écran. C'est le processus de rendu du navigateur que nous avons mentionné ci-dessus.

Afin de terminer le premier rendu le plus rapidement possible, nous devons minimiser les trois variables suivantes:

  • Nombre de ressources critiques: ressources qui peuvent empêcher le premier rendu de la page Web.

  • Longueur du chemin critique: nombre d'allers-retours ou temps total requis pour obtenir toutes les ressources critiques.

  • Section des mots-clés: le nombre total d'octets requis pour obtenir le premier rendu d'une page Web équivaut à la somme des tailles de fichier de toutes les ressources clés.

1. Optimiser le DOM

  • Supprimez le code et les commentaires inutiles, y compris les espaces, et essayez de minimiser les fichiers.
  • Vous pouvez utiliser GZIP pour compresser des fichiers.
  • Combiné avec des fichiers de cache HTTP.

2. Optimiser CSSOM

La réduction, la compression et la mise en cache sont tout aussi importantes. Pour CSSOM, nous avons mentionné plus tôt que cela empêcherait le rendu de la page, nous pouvons donc envisager l'optimisation de cet aspect.

  • Réduisez le nombre d'éléments CSS clés
  • Lorsque nous déclarons des feuilles de style, portez une attention particulière aux types de requêtes multimédias, elles affectent grandement les performances de CRP.

3. Optimiser JavaScript

Lorsque le navigateur rencontre la balise de script, cela empêchera l'analyseur de continuer à fonctionner. Jusqu'à ce que le CSSOM soit construit, JavaScript s'exécutera et continuera à terminer le processus de construction du DOM.

  • async: après avoir ajouté l'attribut async à la balise de script, le navigateur continuera à analyser le DOM lorsqu'il rencontrera cette balise de script, et le script ne sera pas bloqué par CSSOM, c'est-à-dire qu'il ne bloquera pas CRP.

  • Defer: la différence avec async est que le script doit être exécuté après l'analyse du document (avant l'événement DOMContentLoaded), tandis que async permet au script de s'exécuter en arrière-plan pendant l'analyse du document (le processus de téléchargement des deux ne bloquera pas le DOM, mais l'exécution le fera).

  • Lorsque notre script ne modifie pas le DOM ou CSSOM, il est recommandé d'utiliser async.

  • Précharge-précharge et prélecture.

  • Pré-résolution DNS-dns-prefetch.

6. defer 和 async 的区别 ?

Lorsque le navigateur rencontre le script de script:

  • <script src="script.js">
    Sans différer ou asynchrone, le navigateur chargera et exécutera le script spécifié immédiatement. "Immédiatement" fait référence à l'élément de document sous la balise de script avant le rendu, c'est-à-dire qu'il n'attend pas l'élément de document chargé suivant et le charge lorsqu'il est lu. Et exécutez.

  • <script async src="script.js">

Avec async, le processus de chargement et de rendu des éléments de document suivants sera parallèle au chargement et à l'exécution de script.js (asynchrone).

  • <script defer src="myscript.js">
    Avec defer, le processus de chargement des éléments de document suivants sera effectué en parallèle avec le chargement de script.js (asynchrone), mais l'exécution de script.js doit être terminée après que tous les éléments ont été analysés et avant que l'événement DOMContentLoaded ne soit déclenché.

D'un point de vue pratique, il est recommandé de lancer tous les scripts avant, car il s'agit du seul choix d'optimisation pour les anciens navigateurs. Cette méthode peut garantir que tous les autres éléments qui ne sont pas des scripts peuvent être obtenus à la vitesse la plus rapide. Chargement et analyse.

Ensuite, regardons une image:Insérez la description de l'image ici

La ligne bleue représente la lecture réseau et la ligne rouge représente le temps d'exécution, les deux étant pour les scripts. La ligne verte représente l'analyse HTML.

Par conséquent, nous pouvons conclure:

  • Defer et async sont les mêmes dans la lecture réseau (téléchargement), les deux sont asynchrones (par rapport à l'analyse HTML)

  • La différence entre les deux réside dans le moment où le script est exécuté après le téléchargement du script. De toute évidence, le report est le plus proche de nos exigences pour le chargement et l'exécution du script d'application.

  • En ce qui concerne le report, la partie inachevée de cette image est qu'elle exécute les scripts dans l'ordre de chargement, ce qui doit être utilisé à bon escient

  • async est un maître de l'exécution dans le désordre. Quoi qu'il en soit, pour lui, le chargement et l'exécution des scripts sont côte à côte, donc quel que soit l'ordre que vous déclarez, il sera exécuté immédiatement tant qu'il est chargé.

  • Pensez-y attentivement, async n'est pas très utile pour les scripts d'application, car il ne prend pas du tout en compte les dépendances (même l'exécution de l'ordre le plus bas), mais il ne dépend d'aucun script ou script qui ne dépend d'aucun script. Très approprié

7.谈谈浏览器的回流与重绘

回流必将引起重绘,重绘不一定会引起回流。

Reflow

Lorsque la taille, la structure ou certaines propriétés de certains ou de tous les éléments de l'arborescence de rendu changent, le processus de rendu par le navigateur d'une partie ou de la totalité du document est appelé redistribution.

Opérations qui provoqueront un reflux:

Premier rendu de la page

La taille de la fenêtre du navigateur a changé

La taille ou la position de l'élément change. Le contenu de l'élément change (nombre de texte ou taille d'image, etc.)

Modifications de la taille de la police des éléments

Ajouter ou supprimer des éléments DOM visibles

Activer les pseudo-classes CSS (par exemple:: hover)

Interroger certaines propriétés ou appeler certaines méthodes

Certaines propriétés et méthodes couramment utilisées qui provoqueront une refusion:

clientWidth、clientHeight、clientTop、clientLeft

offsetWidth、offsetHeight、offsetTop、offsetLeft

scrollWidth、scrollHeight、scrollTop、scrollLeft

scrollIntoView()、scrollIntoViewIfNeeded()

getComputedStyle()

getBoundingClientRect()

scrollTo()

Repeindre

Lorsque le changement du style d'élément sur la page n'affecte pas sa position dans le flux de documents (par exemple: couleur, couleur d'arrière-plan, visibilité, etc.), le navigateur attribue le nouveau style à l'élément et le redessine. Ce processus est appelé redessiner. peint.

Impact sur les performances

回流比重绘的代价要更高。

Parfois, même si un seul élément est redistribué, son élément parent et tous les éléments qui le suivent seront redistribués. Les navigateurs modernes optimiseront les opérations de redistribution ou de rafraîchissement fréquentes: le navigateur maintiendra une file d'attente et placera toutes les opérations qui provoquent la redistribution et le rafraîchissement dans la file d'attente. Si le nombre de tâches dans la file d'attente ou l'intervalle de temps atteint un seuil, Le navigateur videra la file d'attente et effectuera un traitement par lots, qui peut transformer plusieurs redistributions et redessins en un seul.

Lorsque vous accédez aux propriétés ou méthodes suivantes, le navigateur efface immédiatement la file d'attente:

clientWidth、clientHeight、clientTop、clientLeft


offsetWidth、offsetHeight、offsetTop、offsetLeft


scrollWidth、scrollHeight、scrollTop、scrollLeft


width、height


getComputedStyle()


getBoundingClientRect()

Comme il peut y avoir des opérations dans la file d'attente qui affectent les valeurs de retour de ces propriétés ou méthodes, même si les informations que vous souhaitez obtenir ne sont pas liées aux modifications provoquées par les opérations dans la file d'attente, le navigateur videra de force la file d'attente pour s'assurer que la valeur que vous obtenez est la plus précise. .

Comment éviter

CSS

  • Évitez d'utiliser la mise en page de tableau.

  • Changez la classe à la toute fin de l'arborescence DOM autant que possible.

  • Évitez de définir plusieurs styles en ligne.

  • Appliquez des effets d'animation aux éléments dont l'attribut de position est absolu ou fixe.

  • Évitez d'utiliser des expressions CSS (par exemple: calc ()).

Javascript

  • Pour éviter une manipulation fréquente des styles, il est préférable de réécrire l'attribut de style une fois, ou de définir la liste de styles comme classe et de changer l'attribut de classe une fois.

  • Évitez d'utiliser fréquemment le DOM, créez un documentFragment, appliquez-y toutes les opérations DOM et ajoutez-le enfin au document.

  • Vous pouvez également définir l'affichage: aucun pour l'élément en premier, puis l'afficher une fois l'opération terminée. Parce que les opérations DOM effectuées sur des éléments dont l'attribut d'affichage est aucun ne provoqueront pas de redistribution et de rafraîchissement.

  • Évitez de lire fréquemment les attributs qui entraîneront une redistribution / un rafraîchissement. Si vous avez vraiment besoin de les utiliser plusieurs fois, utilisez une variable pour les mettre en cache.

  • Utilisez un positionnement absolu pour l'élément avec une animation complexe pour le sortir du flux de documents, sinon cela entraînera une redistribution fréquente de l'élément parent et des éléments suivants.

Je suppose que tu aimes

Origine blog.csdn.net/qq_29722281/article/details/105710839
conseillé
Classement