admin管理员组

文章数量:1576747

Recently we started looking a bit into OSBO performance. As the page was built mostly at the time when we didn’t understand front-end development that well (British for: we had no idea what we were doing), plus we didn’t have any active monitoring on performance, various problems obviously managed to sneak in.

If you don’t know Lighthouse, check it out first

关于如何启动Lighthouse的文章很多,其中包含许多非常有用的建议,因此在此我不再重申。 有一个问题是建议不是特别友好:“避免DOM太大”。 在我们的案例中,即使我们的主页和注册页面也有大约3500个DOM节点,并且考虑到它们很简单,这听起来过分。 我们很难理解所有这些节点的来源。 所有建议都围绕“避免创建过多的DOM节点”进行,但我只是找不到有关如何确定在何处(逻辑上在我的代码库中)创建节点的有用信息。 问题出在我代码的哪一部分? 除非您知道需要优化哪个组件,否则很难进行优化。

因此,我迅速淘汰了一个工具来帮助我们发现“ DOM瓶颈”。 而且,尽管我仍然偏爱Java(或更确切地说:这是我生产效率最高的工具),但它在Java中-抱歉;)

Find the DOM branches to trim

该原理实际上非常简单,类似于您突然发现空间不足时如何查找硬盘驱动器上所有空间的位置。 您找到最大的文件夹。 然后是最大文件夹中的最大文件夹。 依此类推,直到您看到可疑的东西为止-一个比通常预期更大的文件夹。

为了做到这一点,而又不花费太多时间编写工具本身(最终我大概花了30分钟),我决定使用JSoup(从我们的网站解析DOM树)和Jackson-尽可能好地打印结果 然后在IntelliJ中轻松折叠/扩展JSON(有用的提示:打开任何.json文件,然后按CTRL-ALT-L缩进一行巨大的JSON)。

The full result is in Github Repo (I have a feeling we might need more stuff to help us with Lighthouse reports). There are two classes in the project:

OsboDomNode-用我们关心的方面来表示DOM的类:子代的总数(以及子代的子节点),以及一些直接子代的基本统计信息。 它使用递归函数来汇总每个DOM元素中的节点总数。

包线上。一站式美容。博客。例子。灯塔。dom;进口com。fasterxml。jackson。annotation。JsonIgnore;进口com。fasterxml。jackson。annotation。JsonPropertyOrder;进口lombok。*;进口org。jsoup。nodes。元件;进口org。jsoup。select。元件s;进口爪哇。效用。清单;进口爪哇。效用。地图;进口爪哇。效用。可选的;进口爪哇。效用。流。收藏家;进口静态的爪哇。效用。馆藏。空清单;进口静态的爪哇。效用。比较器。naturalOrder;进口静态的爪哇。效用。流。收藏家。分组;@数据@Builder@JsonPropertyOrder({“描述”,“类型”,“allChildNodesCount”,“子节点Summary”})上市类OsboDomNode{私人的最后串类型;私人的最后串描述;@JsonIgnore@单数私人的最后清单<OsboDomNode>子节点;@盖特(访问权限。没有)私人的整数allChildNodesCount;上市整型得到AllChildNodesCount(){如果(allChildNodesCount==空值){allChildNodesCount=这个。子节点。尺寸()+这个。子节点。流()。地图ToInt(OsboDomNode::得到AllChildNodesCount)。和();}返回allChildNodesCount;}上市清单<串>得到ChildNodes摘要(){整数allChildNodesCount=这个。得到AllChildNodesCount();返回这个。子节点。流()。地图(儿童->percentInChild(儿童,allChildNodesCount))。收藏(收藏家。to清单());}上市清单<OsboDomNode>得到NodesWithHighestNumberOfChildren(){地图<整数,清单<OsboDomNode>>nodesWithChildCount=子节点。流()。收藏(分组(OsboDomNode::得到AllChildNodesCount));可选的<整数>最高Nodes=nodesWithChildCount。键集()。流()。最高(naturalOrder());如果(最高Nodes。存在()){返回nodesWithChildCount。得到(最高Nodes。得到());}其他{返回空清单();}}私人的串percentInChild(OsboDomNode儿童,整数allChildNodesCount){双百分比=100。0*儿童。得到AllChildNodesCount()/allChildNodesCount;返回串。格式("%d[%。2f%%]in%s%s",儿童。得到AllChildNodesCount(),百分比,儿童。类型,儿童。描述);}上市静态的OsboDomNodefrom元件(元件元件){OsboDomNode。OsboDomNodeBuilder建造者=OsboDomNode。建造者();建造者。类型(元件。标签()。得到Name()+“[”+元件。同级索引()+“]”);建造者。描述(元件。属性()。to串());元件s儿童ren=元件。儿童ren();儿童ren。每次(儿童->建造者。儿童Node(OsboDomNode。from元件(儿童)));返回建造者。建立();}}

OsboPerfHelper-一个简单的运行器,您输入了网站的URL(甚至可以是localhost),它消失了,读取DOM结构,然后将其输入到OsboDomNode中进行分析。

包线上。一站式美容。博客。例子。灯塔。dom;进口com。fasterxml。jackson。databind。对象映射器;进口org。jsoup。汤;进口org。jsoup。nodes。文献;进口org。jsoup。nodes。元件;进口java。io。文件;进口java。io。IOException;上市类OsboPerfHelper{私人的静态的最后对象映射器OBJECT_MAPPER=新对象映射器();上市静态的虚空主要(串[]args)抛出IOException{串osboUrl=“http://localhost:8081”;文献doc=汤。连接(osboUrl)。得到();元件身体=doc。身体();OsboDomNodeosboDomNode=OsboDomNode。from元件(身体);系统。出。打印((整数)osboDomNode。得到AllChildNodesCount());打印杰森(osboDomNode);}私人的静态的虚空打印杰森(OsboDomNodeosboDomNode)抛出IOException{//系统。出。打印(OBJECT_MAPPER。writeValueAs串(osboDomNode));文件result文件=新文件("domNode。json");OBJECT_MAPPER。writeValue(result文件,osboDomNode);系统。出。打印("WrittenJSONresultinto"+result文件。得到AbsolutePath());}}

各自的build.gradle文件

外挂程式{ID'java'}组'online.onestopbeauty.blog.examples'版'1.0-快照sourceCompatibility=1.8仓库{mavenCentral()}依存关系{//https://mvnrepository/artifact/org.jsoup/jsoup编译组:'org.jsoup',名称:'jsoup',版:'1.12.1'//https://mvnrepository/artifact/org.projectlombok/lombok编译Only组:'org.projectlombok',名称:龙目岛,版:'1.18.8'//https://mvnrepository/artifact/com.fasterxml.jackson.core/jackson-databind编译组:'com.fasterxml.jackson.core',名称:'杰克逊-数据绑定',版:'2.9.9'测试编译组:'junit',名称:'junit',版:'4.12'}

哦,是的,我将Lombok用于构造函数,构建器和其他样板文件(getter等)-正是因为Lombok非常出色,这是我始终将其添加到任何Java项目中的第一件事。 只要记住要添加Lombok插件并在IntelliJ中打开注释处理,否则您会遇到编译错误。

Our real-world experience

那么在实时版本上运行时,我们的情况如何? 头几个级别的节点看起来相当健康,主体子节点和直接子节点各包含约99%的节点(只需几层包装器,无需担心)。 但是随后我看到了一些可疑的东西(这里是Vuetify的技巧提示,它们在组件中使用了有意义的类名-使故障排除变得非常容易):

{
"description": " class=\"application--wrap\"",
"type": "div[0]",
"allChildNodesCount": 3401,
"childNodesSummary": [
  "[39.05] in div[2] class=\"layout\" data-v-3a808de6",
  "[56.40] in main[4] class=\"v-content\" style=\"padding-top:0px;padding-right:0px;padding-bottom:56px;padding-left:0px;\"",
  "[4.38] in footer[6] data-cy=\"osboFooter\" class=\"v-footer v-footer--absolute v-footer--inset theme--light\" style=\"height:auto;margin-bottom:56px;border-radius:10px;\" data-v-3645c51c",
  "[0.06] in button[8] type=\"button\" medium=\"\" class=\"v-btn v-btn--bottom v-btn--floating v-btn--fixed v-btn--right v-btn--small theme--dark secondary fab-style\" style=\"display:none;\" data-v-045da490"
]}

我们应用程序的“主要”部分占用了不到60%的节点,“ div [2] /布局”元素占用了近40%。 此时,我在OsboPerfHelper中添加了一个额外的log语句,以深入到正确的节点中。 当然,可以用一种更好的方式来完成此操作,如果我不得不更频繁地使用它,也许我会添加一些更好的“向下钻取”工具-但在此时,这是一项“快速而肮脏的”工作 一个小时左右-并且做得很好:

printJson(osboDomNode.getNodesWithHighestNumberOfChildren().get(0)
                .getNodesWithHighestNumberOfChildren().get(0)
                .getNodesWithHighestNumberOfChildren().get(0)
                .getNodesWithHighestNumberOfChildren().get(0)
                .getChildNodes().get(0));

结果是:

{
"description": " class=\"flex offset-md1 md10 xs12\" data-v-3a808de6",
"type": "div[0]",
"allChildNodesCount": 1327,
"childNodesSummary": [
   "[0.45] in div[0] class=\"layout\" data-v-0c4978b8 data-v-3a808de6",
   "[65.49] in aside[2] data-cy=\"mobileNavBar\" class=\"offWhite1 v-navigation-drawer v-navigation-drawer--clipped v-navigation-drawer--close v-navigation-drawer--fixed v-navigation-drawer--temporary theme--light\" style=\"height:100%;margin-top:0px;transform:translateX(-375px);width:375px;\" data-v-c332d172 data-v-3a808de6",
    "[33.84] in nav[4] id=\"attachMenu\" data-cy=\"osboToolBar\" class=\" text-xs-center px-0 toolbarStyle v-toolbar elevation-0 v-toolbar--dense v-toolbar--extended theme--light\" style=\"margin-top:0px;padding-right:0px;padding-left:0px;transform:translateY(0px);\" data-v-3a808de6"
]}

这使我看到我的移动导航栏中有近900个节点。 有趣的是,我甚至不需要在页面的桌面版本上使用mobileNavbar(带有菜单的移动版本),这是我目前正在测试的。 因此,我们开始进行一些简单的清理工作,以减小移动菜单的大小(900个节点在需要时听起来有些多余),并确保它不是在桌面上生成的(因为这很浪费并且从未显示)。

这仅仅是修剪DOM树的开始(我们现在在localhost上大约有1700个节点,因此进行了大幅度的缩减,并且还有更多)–但关键是要知道修剪哪个DOM“分支”。

Is there anything better out there?

如果您知道这项工作的更好工具,请在下面的评论中留下注释。 我很难相信这样一个简单的问题尚不存在-但是快速的google搜索使我获得了大部分结果,其中包含许多描述大型DOM为何不好的文章-而不是如何在DOM树中找到最严重的违规者 。 否则,请随时报告此“微型工具”是否有任何帮助。

from: https://dev.to//lilianaziolek/solving-lighthouse-avoid-an-excessive-dom-size-issue-4b7b

本文标签: LighthouseDOM