Nous profilons le chargement de Habr ou comment 189 requêtes sur la page rendent l'influence

Prenez du jus de cerise épais


Il y a quelque temps, je me suis intéressé aux performances du site Web, aux optimisations de téléchargement, etc. Et maintenant, en allant une fois de plus au Habr, je pensais que j'avais l'habitude de percevoir une charge de ressources assez rapide comme une donnée, sans même penser à la façon dont cela était réalisé. J'ai donc décidé de combiner affaires et plaisir - pour voir comment les choses évoluent avec les performances d'Habr et quelles solutions techniques ont été mises en place pour les optimiser.


Pour ceux qui souhaitent savoir ce qui a été fait afin que nous recevions le contenu le plus rapidement possible et à quoi ressemble le téléchargement du Habr d'Argentine - s'il vous plaît, sous cat.


La préparation


Nous aurons besoin d'une nouvelle version de Chrome / Canary fonctionnant en mode anonyme (assurez-vous que toutes les extensions sont désactivées). De plus, dans la console développeur (Developer Tools - F12), dans l'onglet réseau, vous devez définir l'indicateur de désactivation du cache, car Nous ne profilerons que le premier démarrage, alors qu'il n'y a pas encore de ressources dans le cache.


Première étape - "A l'étage"


L'objectif principal de cette partie est de se familiariser avec le site dans son ensemble, de comprendre sa structure et de savoir de quelles ressources spécifiques il a besoin.


Nous ouvrons les outils de développement, allons dans l'onglet réseau, ouvrons le site et tout en bas de l'onglet nous regardons les statistiques sur l'utilisation du réseau:


Et une cape de mère blanche.


L'ensemble du site a été chargé en 2,02 secondes, ce qui est tout simplement génial (compte tenu de la charge de Habr). L'événement DomContentLoaded (ci-après simplement DCL) est généralement apparu en 1,01 seconde, ce qui est encore mieux. Avec tout cela, le site fait 189 demandes et charge 9,6 Mo de ressources. Cela nous dit que soit l'équipe Habra est un génie (cela pourrait bien l'être), et l'article devrait être terminé ici (et demandez-le à l'équipe pour le café et les cookies), ou rappelez-vous que j'ai une chaîne à 100 Mb / s et Core I7 . C'est-à-dire vous devez vous rapprocher un peu plus de la réalité et au moins limiter la largeur du canal.


Nous activons le mode Fast 3G et regardons à nouveau:


Versez doucement le jus sur la cape -


DCL a empiré à 3,48 secondes, ce qui est encore raisonnablement acceptable. Mais finalement le site s'est chargé en 54,76 secondes athées. Maintenant, tout est logique - vous ne pouvez pas simplement télécharger et télécharger près de 10 mégaoctets lorsque votre connexion est faible. Très probablement, les gars ont fait du bon travail pour nous montrer le contenu le plus rapidement possible (cela est démontré par le fait que même en mode fast3g DCL apparaît assez rapidement), et ils ont laissé tout ce qui n'était pas critique à charger en arrière-plan. Nous allons vérifier cela un peu plus tard, et voyons maintenant pourquoi nous avons chargé si longtemps. Trier toutes les demandes par temps de chargement:


Un spot apparaîtra.
Cliquable


Les images (top-7) sont chargées le plus longtemps et un fichier JavaScript est prebid.js. Si nous regardons leur taille, nous pouvons supposer que c'est précisément la raison du chargement lent.


À propos des hypothèses

Avec des hypothèses, vous devez être extrêmement prudent. Ainsi, par exemple, un long chargement d'une ressource peut être causé non seulement par la taille du fichier, mais aussi, par exemple, des problèmes avec DNS, une charge de stockage maximale ou un cache de serveur froid. Par conséquent, une hypothèse non vérifiée peut vous faire perdre du temps à résoudre un problème qui n'existe même pas.


En regardant les statistiques ( TTFB : 0,610 ms, charge: 40 000 ms), nous pouvons conclure que notre hypothèse est tout à fait probable. Admirons notre TOP 1 (png, 1560X780, 24 bits):


Maintenant qu'il n'y a plus de place


En fait, les problèmes d'images sont principalement des problèmes de trafic avec vous. Les images (contrairement aux styles et aux scripts) ne bloquent pas le rendu de la page Web, et donc, malgré la présence de tels poids lourds (cela peut être pire, ils l'ont vu), cela n'a presque aucun effet sur les performances. Bien sûr, l'optimisation dans ce sens (par exemple, le transcodage en jpeg2000 ou webp, ou le chargement progressif ne serait pas superflue).


À propos des images

Comme je l'ai écrit ci-dessus, les images ne bloquent pas le rendu de la page. Mais ils utilisent notre pool de connexions, et dans http 1.x leur nombre est limité, et avec http 2.x et Chrome aussi, tout n'est pas aussi fluide que ce que j'ai entendu. Par conséquent, même ici, il est possible qu'une image ralentisse le chargement d'un script synchrone et que, à son tour, elle arrête déjà le rendu de la page. De plus, le chargement de l'image peut également provoquer un recomptage de la mise en page, ralentissant ainsi le rendu. Si nous regardons le balisage Habr, presque toutes les balises img ont une largeur et une hauteur. Cela élimine le besoin de refusion pour avoir un impact positif sur les performances de téléchargement. Vous pouvez en savoir plus à ce sujet ici .


Voyons quelles autres ressources le Habr tire - nous allons passer en revue les types et les trier par temps de chargement. Commençons par JavaScript


Javascript


À propos de javascript

JavaScript présente plusieurs problèmes en termes de performances du site. Tout d'abord (tout le monde le sait depuis longtemps), js synchrone bloque le rendu des pages. C'est-à-dire jusqu'à ce que nous recevions et exécutions notre JavaScript, le navigateur attendra (en fait pas tout à fait, le navigateur, en particulier Chrome, peut optimiser, mais c'est une autre histoire) et ne restituera pas de contenu supplémentaire. En utilisant des scripts synchrones dans la tête, nous reportons le moment où l'utilisateur voit au moins quelque chose (même du texte). Par conséquent, tout le monde essaie de lancer Js à la fin de la page ou même de le rendre asynchrone. Cela fonctionne, mais ne résout pas le deuxième problème qui nous amène au fait que JavaScript est toujours un langage de script. Par conséquent, le navigateur ne suffit pas simplement pour le télécharger - il doit également être «compris». Et ici, il s'avère que c'est un problème, car les processeurs faibles (par exemple, dans les téléphones ou netbooks bon marché, ou même les bons ordinateurs portables en mode de performance limitée) le font lentement, bloquant le thread principal! Vous trouverez ci-dessous un exemple de la façon dont un script publicitaire asynchrone est entré dans la section critique du rendu Habr et bien qu'un peu, mais a encore gâché les performances. Si quelqu'un est intéressé, il y a un très (très, très) bon article sur ce sujet.


Les scripts Habr chargent beaucoup - 1,1 Mo (et c'est déjà sous une forme compressée) pour 40 demandes. C'est franchement significatif, cela nous revient encore et nous devons y faire quelque chose. Trier nos scripts "par la cascade". Notre tâche est de trouver les scripts chargés AVANT la ligne bleue, car ce sont eux (très probablement) qui nous empêchent de rendre le site le plus rapidement possible.


Sur le manteau de ma mère
Cliquable


Nous ouvrons le html que Habr nous a donné (il est important de regarder la réponse, car le html final sera différent) et parcourons la liste. Comme vous pouvez le voir - jQuery, raven.js, advertise.js et adriver.js sont chargés de manière synchrone directement à partir de la balise head (c'est-à-dire qu'ils bloquent tout). Gpt et l'éditeur sont chargés à partir de head mais déjà de manière asynchrone (c'est-à-dire qu'ils ne bloquent rien, le navigateur rendra la page plus loin pendant le chargement). Vendors, Main et Math, checklogin sont chargés à la fin, mais de manière synchrone (c'est-à-dire que le texte est déjà là, nous pouvons le lire, mais le DCL n'apparaîtra pas avant le chargement). Les autres n'apparaissent pas dans la réponse initiale - ils sont ajoutés dynamiquement, mais c'est un autre sujet.


Nous avons donc trouvé ces scripts qui affectent en quelque sorte la vitesse à laquelle nous voyons le texte sur la page. Ce sont les premiers candidats à l'optimisation. Idéalement, ils devraient être rendus asynchrones ou placés aussi bas que possible pour permettre au navigateur de rendre le contenu pour nous. Cependant, l'idéal n'est pas réalisable, car il y a très probablement d'autres scripts sur le site qui dépendent du même jQuery. L'envie de télécharger le corbeau au plus vite - une bibliothèque de suivi des diverses erreurs qui se produisent sur le client, peut également être comprise. Mais advertise.js et adriver.js sont déjà de vrais candidats pour au moins descendre la page, et au maximum aussi en mode asynchrone. Une histoire similaire avec gpt et éditeur. Oui, ils sont chargés de manière asynchrone, mais, néanmoins, ils peuvent (et vont) interférer avec nous lors du chargement. Par conséquent, ils pourraient également être envoyés tout en bas de la page. De plus, vous pouvez essayer d'utiliser les attributs Resource Hints - preload / prefetch / dns-prefetch pour indiquer au navigateur quoi charger à l'avance. Soit dit en passant, je vous conseille de lire les conseils sur les ressources - un outil très intéressant, bien qu'avec un support limité (jusqu'à présent).


Triez maintenant la liste par taille de fichier:


Le manteau doit être rentré entier
https://github.com/Drag13/articles/blob/habrformance/habrformance/scripts.PNG


Nous voyons un script qui se charge deux fois (pubades). Nous remarquons également que prebid.js est chargé à partir du dossier not-for-prod


Dans un jus de cerise épais.


Pour vider notre conscience, nous vérifions que tous les scripts sont minifiés. Du coup, les scripts check-login.js et adriver.js n'ont pas été minifiés. Particulièrement satisfait du contenu de ce dernier:


Prenez une cape de maman cerise


Et avec des scripts, vous pouvez temporairement arrêter.


Les styles


À propos des styles

Avec les styles, tout n'est pas si simple. Premièrement, le chargement synchrone des styles bloque également le thread principal (bien qu'ils soient analysés rapidement, plus rapidement que JavaScript). Et deuxièmement, tout est un peu plus compliqué. Pourquoi le navigateur a-t-il besoin de CSS? Pour construire CSSOM . Que peut faire JavaScript avec CSS? C'est vrai - changez. Et que se passera-t-il si CSSOM n'est pas encore construit et que js essaie déjà de changer quelque chose là-bas? La réponse est qui sait. Par conséquent, le navigateur retarde l'exécution de JavaScript jusqu'à ce que le CSSOM soit calculé. Comme correctement écrit dans un autre article très utile - pas de CSS = pas de JavaScript. Par conséquent, le chargement de CSS bloque l'exécution de JS.


Voici les styles que Habr charge:


Et une tasse de lait.
Cliquable


Comme vous pouvez le voir, il n'y en a que trois, les deuxième et troisième étant chargés dans un cadre séparé, nous les ignorons donc. Mais le premier ensemble de styles est crucial pour l'ensemble du site. Et nous l'avons téléchargé depuis très longtemps. Pourquoi? Premièrement, ils ont attendu longtemps une réponse du serveur (TTFB 570 ms, nous y reviendrons dans la troisième section), et deuxièmement, 713 ms ont été chargés pendant longtemps. Que peut-on faire ici. La première et la plus simple consiste à essayer d'ajouter l'attribut de précharge. Cela demandera au navigateur de commencer à charger CSS le plus tôt possible. La deuxième option consiste à mettre en évidence le CSS critique et à l'intégrer directement dans la page Web, et à charger le reste de manière synchrone (ou même asynchrone). Cela entraînera une augmentation de la taille de la page (mais elle n'est déjà pas petite et + 5 ko ne gâchera rien) et un éventuel redessin de la mise en page (perte de temps), mais vous pouvez essayer.


Je ne montrerai même pas les polices. Il est là seul, bien que pour une raison quelconque, il soit chargé directement à partir du serveur Habr au lieu du CDN (et probablement pour une raison). Mais je dirai merci pour le fait qu'il n'y a qu'une seule police.


Sur ce point, la partie aperçu de l'analyse du site peut être considérée comme terminée. Il est temps d'aller plus loin.


Deuxième étape - "Mode manuel"


À la dernière étape, nous avons vu que Habr se charge. Nous allons maintenant voir comment cela est rendu.


Accédez à l'onglet de profilage. Nous vérifions ce qu'est le ralentissement fast3g (puis réexécutons sans restrictions) et exécutons. Tout d'abord, nous sommes intéressés par tout ce qui se passe avant l'événement First contentful paint (FCP) et, juste au cas où, DCL. Nous sélectionnons la zone depuis le début du chargement sur FCP et regardons le schéma final.


Versez le lait soigneusement -


Tout se passe assez rapidement - 2,161 secondes avant FCP (c'était plus rapide, mais apparemment quelque chose avait changé), mais comme vous pouvez le voir, la plupart du temps le navigateur était inactif. La charge utile ne prenait que 14% du temps (environ 310 ms). Idéalement, le thread principal du navigateur s'exécute en continu - l'analyse HTML, CSS, exécute JS. Et ici - rien. Pourquoi? Parce que le navigateur n'avait rien à voir. Rappelez-vous que nous avons réduit le trafic? Le navigateur a envoyé des demandes et attend maintenant qu'elles soient terminées. Si nous ouvrons le diagramme des processus réseau (le plus haut), tout deviendra immédiatement clair.


Un spot apparaîtra.
Cliquable


En 2029, le navigateur a vu main.bundle.css, a envoyé une demande pour le recevoir et a commencé à attendre. À ce moment, le préscanner (smart chrome, il peut aller de l'avant) a découvert qu'il y avait des scripts synchrones ci-dessous et sans attendre l'arrivée de CSS, il a envoyé une demande de scripts. Ensuite, la publicité et l'adriver sont chargés (mais nous nous souvenons que même si CSSOM n'est pas créé, vous ne pouvez pas toucher JS), le navigateur les a donc ignorés. Après cela, gpt et raven se sont chargés, mais le CSS était toujours en cours de chargement, ils ont donc également été ignorés. Enfin, CSS a été chargé, que le navigateur a analysé en 12 ms et a immédiatement analysé le JS intégré dans la page. Ensuite, le navigateur s'est à nouveau «endormi» à près de 150 ms en attendant jQuery.min.js. Et après cela, j'ai déjà commencé à travailler sérieusement - j'ai compris le jQuery chargé (20 ms), analysé raven.js (4 ms), analysé presque toute la page (36 ms), raconté les styles (28 ms), calculé la disposition (78 ms + 8 ms) et, enfin, pendant ~ 6 ms, nous avons peint la page. Ici, nous avons FCP. Ensuite, nous analysons la page, analysons les scripts - bonjour à personne (publishertag.js, gpt.js qui est entré dans le thread principal avant DCL), avons joué un peu avec les styles (ce qui a causé une légère perte de temps en raison du recalcul de la mise en page) et avons commencé à attendre les fournisseurs. bundle.js. Afin d'attendre les vendeurs, nous avons presque inactif passé encore 1100 ms. Certes, en parallèle, nous avons également chargé main.bundle.js (qui, incidemment, a démarré plus rapidement), donc tout n'est pas si mauvais. Puis tout s'est encore bien passé. Nous avons analysé les fournisseurs, analysé le bundle principal, analysé Math.Jax, et finalement analysé la page et obtenu DCL. Certes, une sorte de gestionnaire a fonctionné là-bas, ce qui sur mon I7 a arrêté le thread principal à 80 ms (c'est-à-dire que le site semblait geler à 80 ms). Maintenant, nous n'avons presque pas remarqué cela, mais sur un processeur faible, théoriquement, cela peut être perceptible. Si vous voyez cela après le rendu du contenu, c'est l'occasion de vérifier JS.


Que puis-je dire. Encore une fois, malgré le fait qu'il semble assez bon. Les principaux problèmes nous ont été livrés:


  • Un grand navigateur simple (notamment en raison du déséquilibre artificiel entre la puissance de calcul de l'ordinateur et la largeur du canal, mais c'est aussi un scénario tout à fait valable)
  • Long chargement CSS qui a retardé le travail avec js critiques
  • Chargement synchrone de jQuery, des fournisseurs et des bundles principaux qui a arrêté l'apparition du contenu.

Ce que nous pouvons faire avec cela, nous avons déjà discuté:


  • Essayez d'ajouter l'attribut de précharge pour CSS et peut-être certains JS
  • Réduire ou incorporer CSS
  • Essayez généralement de jeter les scripts hors du chargement synchrone (au moins certains)

Maintenant, répétons la même chose sans aucune restriction sur la largeur du canal. L'image est déjà bien meilleure: 0,452 seconde en FMP, la plus simple de toutes! 13 ms. DCL - 953 ms, simple 15 ms. Voici à quoi ressemble mon téléchargement de rêve. C'est exactement ce qui s'est passé parce que j'ai ouvert un nouvel onglet et que je n'ai pas supprimé la mise en cache. Essayons la même chose, mais sans cache:


Maintenant qu'il n'y a plus de place


Tout est également assez bon, FCP / FMP - 1689, charge utile 45%. Soit dit en passant, l'ajustement de la charge à 100% est également mauvais, car les machines plus faibles seront surchargées. Il est donc préférable d'avoir une réserve pour les temps d'arrêt. Mais ici, de manière inattendue, beaucoup de temps a été consacré au rendu - 400 ms pour FMP. Parmi ceux-ci, 200 ms ont été recalculés dans les styles et recalculés dans la disposition.


Au fait, un autre point intéressant. Vous vous souvenez des scripts publicitaires - gpt.js et publishertag.js qui ont été mentionnés dans la première partie? Maintenant, vous pouvez voir que malgré leur asynchronie, ils ont pu (quoique un peu) ruiner nos statistiques. Cela est dû au fait que l'exécution des scripts asynchrones se fait en fonction de l'état de préparation des scripts eux-mêmes. C'est-à-dire cela peut arriver à tout moment, y compris avant FCP / DCL, ce qui s'est produit en 3309.


Nous avons donc fait le démontage manuel. Il est temps de découvrir l'automatisation.


Troisième étape - «Nous devions partir de là»


À propos de la ferme collective

Je pense que tout le monde comprend que cette étude est très arbitraire. Au moins, parce que tout le temps pendant que je testais de nouveaux articles apparaissaient, la charge sur le serveur et la charge sur les dorsales du réseau changeaient. Dans le bon sens, vous devez déployer un serveur dédié dans lequel personne n'écrira quoi que ce soit, émulera la charge pertinente avec des retards pertinents, puis profilera quelque chose. Sinon, vous pouvez faire quelques hypothèses, (par exemple, sur la nécessité d'ajouter un attribut de précharge sur CSS), l'ajouter, le déployer en production, puis il s'avère que la charge pendant le test a fortement augmenté et le serveur nous a donné le même style 500 ms plus tard. Et il s'avère que la précharge est mauvaise - cela a simplement aggravé tout. Et l'auteur est le dernier radis du tout. En outre, le profilage manuel (comme dans la deuxième partie), jusqu'à ce que vous fuyiez tous les outils automatiques et résolviez les problèmes qui s'y trouvent, n'a également aucun sens, car après vos premiers changements, l'image changera.


Par conséquent, avant toute expérience, nous avons besoin de l'environnement le plus stable. Cette fois. La seconde - vous ne devriez jamais aller en profondeur (par exemple, dans le profilage) dès le début. Démarrez d'abord les outils automatiques, laissez-les fonctionner pour vous. Collectez des rapports, voyez ce qui peut être fait le mieux possible en un minimum de temps. Essayez de le faire. Si possible, vous en avez peut-être déjà assez. Par exemple, votre css.bundle pèse 100 Ko, mais en réalité, vous avez besoin de 45 Ko (à propos, la situation réelle: ils ont pris tout le bootstrap, mais seule la grille était nécessaire). Ils ont réduit la taille des styles et ont gagné une demi-seconde pratiquement pour rien. Ce sont deux. Vérifiez toujours deux fois. Il semblerait que les styles soient en ligne, tout devrait s'améliorer, mais ça va empirer. Pourquoi? Et parce que dans les styles d'images 50kb base64, et notre page vient de charger 200kb de ressources. N'oubliez pas qu'il n'y a pas de solution miracle et de scripts universels. Ce sont trois. Et la dernière, même si elle contredit la phrase précédente. Si vous n'avez pas de site compliqué, surveillez simplement TTFB (problèmes de serveur), la taille des ressources téléchargées (bonjour aux logos pour 2 Mo) et ne donnez pas accès à Google Tag Manager-personne. Ce sera probablement assez.


Nous n'irons pas loin, dans les mêmes outils de développement, ouvrez l'onglet d'audit et lancez LightHouse (LH) avec les paramètres suivants: bureau, performances uniquement, pas de limitation, stockage clair. Après avoir attendu un peu (ne quittez pas la page sur laquelle l'audit est en cours et ne faites rien de mieux) nous obtenons des chiffres fantastiques (même avec le cache désactivé)


Sur le manteau de ma mère


Il me semble même qu'ils ont été spécialement adaptés à ces figures.


Cependant, LH se plaint toujours de:


  • Format d'image obsolète (suggère d'utiliser webp, jpeg2000, etc.)
  • DOM node – : 2533, 1500.
  • — 23
  • document.write

. (), DOM — node (-), ( ), document.write- writer ( - )


( ) . , , , . , , . CSS, — , , JavaScript. , , . .


, fast3g , , ( I7, celeron):



( FCP 3500 ms, FMP 5.7):


  • , . LH next-gen , , , 11
  • . adriver.js advertise.js 50 , .
  • CSS , 5kb 45kb.
  • main thread. JavaScript — (8.5 script evaluation 2186 ms raven.js). ?

? . - . :


  • DOM
  • JavaScript

, , (, raven.js).


, , — webpagetest.org


— , , . — , . , . , , . , , , — -.


https://habr.com ( ru/en ).


.


( , )


. ( ) DNS (500 ms ), , ssl . , 1150 ms c ( ). , ( habrastorage).


main.bundle.css. , dr.habracdn.net , dns lookup — 36 ms ( 400 ms). SSL negotiation 606 ms, TTFB 601 ms, . . DCL — 4100 ms , .


image analysis , , . - PNG 1.4, webp + downscaling ( , ) — 17.7 KB. , , png 154. . , :


  • ( , , .. ).
  • . , .
  • TTFB (webpagetest F ) —
  • , ( )

Conclusions


. :


:


  • TTFB 500 ms ( dns, ssl initial connection)
  • habrastorage

:


  • DOM-a

, , . , , . , SPA, , JS — . . //,


Liens utiles



PS. ( ) . , .1, .2, .3 .

Source: https://habr.com/ru/post/fr454444/


All Articles