Heim > Artikel > Web-Frontend > Lassen Sie uns darüber sprechen, wie CSS und JS das Parsen und Rendern von DOM blockieren
In diesem Artikel erfahren Sie, wie CSS und JS das Parsen und Rendern von DOM blockieren. Es hat einen gewissen Referenzwert. Freunde in Not können sich darauf beziehen. Ich hoffe, es wird für alle hilfreich sein.
Hallo~ Liebe Leserinnen und Leser, hallo zusammen. Ich schätze, jeder hat schon einmal davon gehört, dass versucht wird, CSS
am Anfang und JS
am Ende einzufügen, was die Leistung der Seite verbessern kann. Aber warum? Haben Sie darüber nachgedacht? Ich wusste es lange Zeit, wusste aber nicht warum. Natürlich war es in Ordnung, es auswendig zu lernen, um mit der Beurteilung fertig zu werden, aber in der tatsächlichen Anwendung wäre es ein Chaos. Waschen Sie also (wang) Herz (yang) Leder (bu) Gesicht (lao) und fassen Sie die jüngsten Ergebnisse zusammen. CSS
放头部,JS
放底部,这样可以提高页面的性能。然而,为什么呢?大家有考虑过么?很长一段时间,我都是知其然而不知其所以然,强行背下来应付考核当然可以,但实际应用中必然一塌糊涂。因此洗(wang)心(yang)革(bu)面(lao),小结一下最近玩出来的成果。
友情提示,本文也是小白向为主,如果直接想看结论可以拉到最下面看的~
由于关系到文件的读取,那是肯定需要服务器的,我会把全部的文件放在github上,给我点个 star 我会开心!
node
端唯一需要解释一下的是这个函数:
function sleep(time) { return new Promise(function(res) { setTimeout(() => { res() }, time); }) }
嗯!其实就延时啦。如果CSS
或者JS
文件名有sleep3000
之类的前缀时,意思就是延迟3000毫秒才会返回这文件。
下文使用的HTML
文件是长这样的:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Title</title> <style> div { width: 100px; height: 100px; background: lightgreen; } </style> </head> <body> <div></div> </body> </html>
我会在其中插入不同的JS
和CSS
。
而使用的common.css
,不论有没有前缀,内容都是这样的:
div { background: lightblue; }
好了,话不多数,开始正文!
关于CSS
,大家肯定都知道的是2cdf5bf648cf2f33323966d7f58a7f3f
标签放在头部性能会高一点,少一点人知道如果3f1c4e4b6b16bbbd69b2ee476dc4f83a
与2cdf5bf648cf2f33323966d7f58a7f3f
同时在头部的话,3f1c4e4b6b16bbbd69b2ee476dc4f83a
在上可能会更好。这是为什么呢?下面我们一起来看一下CSS
对DOM
的影响是什么。
CSS
不会阻塞 DOM
的解析注意哦!这里说的是DOM
解析,证明的例子如下,首先在头部插入724fcbbec47717ef0e05b73b5abe9f462cacc6d41bbb37262a98f745aa00fbf0
,JS
文件的内容是:
const div = document.querySelector('div'); console.log(div);
defer
属性相信大家也很熟悉了,MDN对此的描述是用来通知浏览器该脚本将在文档完成解析后,触发 DOMContentLoaded 事件前执行。设置这个属性,能保证DOM
解析后马上打印出div
。
之后将5e9002b65a9ea31649480429c16b6316
插入HTML
文件的任一位置,打开浏览器,可以看到是首先打印出div
这个DOM
节点,过3s左右之后才渲染出一个浅蓝色的div
。这就证明了CSS
是不会阻塞 DOM
的解析的,尽管CSS
下载需要3s,但这个过程中,浏览器不会傻等着CSS
下载完,而是会解析DOM
的。
这里简单说一下,浏览器是解析DOM
生成DOM Tree
,结合CSS
生成的CSS Tree
,最终组成render tree
,再渲染页面。由此可见,在此过程中CSS
完全无法影响DOM Tree
,因而无需阻塞DOM
解析。然而,DOM Tree
和CSS Tree
会组合成render tree
,那CSS
会不会页面阻塞渲染呢?
CSS
阻塞页面渲染其实这一点,刚才的例子已经说明了,如果CSS
不会阻塞页面阻塞渲染,那么CSS
文件下载之前,浏览器就会渲染出一个浅绿色的div
,之后再变成浅蓝色。浏览器的这个策略其实很明智的,想象一下,如果没有这个策略,页面首先会呈现出一个原始的模样,待CSS
下载完之后又突然变了一个模样。用户体验可谓极差,而且渲染是有成本的。
因此,基于性能与用户体验的考虑,浏览器会尽量减少渲染的次数,CSS
顺理成章地阻塞页面渲染。
然而,事情总有奇怪的,请看这例子,HTML
node
-Seite erklärt werden muss, ist diese Funktion: 🎜<header> <link rel="stylesheet" href="/css/sleep3000-common.css"> <script src="/js/logDiv.js"></script> </header>🎜Hmm! Tatsächlich ist es verzögert. Wenn der Dateiname
CSS
oder JS
ein Präfix wie sleep3000
hat, bedeutet dies, dass die Datei nach einer Verzögerung von 3000 Millisekunden zurückgegeben wird. 🎜🎜Die unten verwendete HTML
-Datei sieht so aus: 🎜const arr = []; for (let i = 0; i < 10000000; i++) { arr.push(i); arr.splice(i % 3, i % 7, i % 5); } const div = document.querySelector('div'); console.log(div);🎜Ich werde verschiedene
JS
und CSS
darin einfügen. 🎜🎜Die verwendete common.css
, unabhängig davon, ob ein Präfix vorhanden ist oder nicht, der Inhalt ist wie folgt: 🎜<body> <div></div> <script src="/js/sleep3000-logDiv.js"></script> <style> div { background: lightgrey; } </style> <script src="/js/sleep5000-logDiv.js"></script> <link rel="stylesheet" href="/css/common.css"> </body>🎜Okay, ohne viel zu sagen, fangen wir mit dem Text an! 🎜
CSS
muss jeder wissen, dass 2cdf5bf648cf2f33323966d7f58a7f3f-Tag im Header zu platzieren, ist höher, wenn <code>3f1c4e4b6b16bbbd69b2ee476dc4f83a
und 2cdf5bf648cf2f33323966d7f58a7f3f
gleichzeitig im Header stehen , 3f1c4e4b6b16bbbd69b2ee476dc4f83a
könnte besser sein. Warum ist das so? Werfen wir einen Blick auf die Auswirkungen von CSS
auf DOM
. 🎜CSS
blockiert nicht das Parsen von DOM
DOM
. Fügen Sie zunächst 0ae1b4d46209f6ceeffd5e5bfdf0d62e2ec882c35fbb0f761ebb4197008f6f04
an einer beliebigen Stelle der HTML
-Datei ein und öffnen Sie die Browser Im Browser können Sie sehen, dass der DOM
-Knoten von div
zuerst gedruckt wird und dann nach etwa 3 Tagen ein hellblaues div
gerendert wird Sekunden. Dies beweist, dass CSS
das Parsen von DOM
nicht blockiert. Obwohl der Download von CSS
3 Sekunden dauert, wartet der Browser nicht einfach bis CSS
wird heruntergeladen und analysiert stattdessen DOM
. 🎜🎜Um es einfach auszudrücken: Der Browser analysiert DOM
, um einen DOM-Baum
zu generieren, und kombiniert CSS
, um einen CSS-Baum
zu generieren >, bilden Sie schließlich einen Renderbaum
und rendern Sie dann die Seite. Es ist ersichtlich, dass CSS
während dieses Vorgangs überhaupt keinen Einfluss auf DOM Tree
hat, sodass keine Notwendigkeit besteht, die Analyse von DOM
zu blockieren. DOM Tree
und CSS Tree
werden jedoch zu render tree
kombiniert. Dadurch blockiert CSS
das Rendern der Seite ? 🎜CSS
blockiert das Rendern von SeitenCSS
-Datei heruntergeladen wird, rendert der Browser also ein hellgrünes div
und dann dieses wird hellgrün. Diese Strategie des Browsers ist eigentlich sehr klug. Stellen Sie sich vor, dass die Seite ohne diese Strategie zunächst ihr ursprüngliches Aussehen zeigen würde und dann plötzlich ihr Aussehen ändern würde, nachdem CSS
heruntergeladen wurde. Die Benutzererfahrung ist äußerst schlecht und das Rendern ist kostspielig. 🎜🎜Daher wird der Browser basierend auf Leistungs- und Benutzererfahrungsüberlegungen versuchen, die Anzahl der Renderings zu reduzieren, und CSS
blockiert natürlich das Seitenrendering. 🎜🎜Aber die Dinge sind immer seltsam. Schauen Sie sich dieses Beispiel an. Die Header-Struktur von HTML
lautet wie folgt: 🎜rrreee🎜Aber denken Sie darüber nach, was passieren wird. 🎜答案是浏览器会转圈圈三秒,但此过程中不会打印任何东西,之后呈现出一个浅蓝色的div
,再打印出null
。结果好像是CSS
不单阻塞了页面渲染,还阻塞了DOM
的解析啊!稍等,在你打算掀桌子疯狂吐槽我之前,请先思考一下是什么阻塞了DOM
的解析,刚才已经证明了CSS
是不会阻塞的,那么阻塞了页面解析其实是JS
!但明明JS
的代码如此简单,肯定不会阻塞这么久,那就是JS
在等待CSS
的下载,这是为什么呢?
仔细思考一下,其实这样做是有道理的,如果脚本的内容是获取元素的样式,宽高等CSS
控制的属性,浏览器是需要计算的,也就是依赖于CSS
。浏览器也无法感知脚本内容到底是什么,为避免样式获取,因而只好等前面所有的样式下载完后,再执行JS
。因而造成了之前例子的情况。
所以,看官大人明白为何3f1c4e4b6b16bbbd69b2ee476dc4f83a
与2cdf5bf648cf2f33323966d7f58a7f3f
同时在头部的话,3f1c4e4b6b16bbbd69b2ee476dc4f83a
在上可能会更好了么?之所以是可能,是因为如果2cdf5bf648cf2f33323966d7f58a7f3f
的内容下载更快的话,是没影响的,但反过来的话,JS
就要等待了,然而这些等待的时间是完全不必要的。
JS
,也就是3f1c4e4b6b16bbbd69b2ee476dc4f83a
标签,估计大家都很熟悉了,不就是阻塞DOM
解析和渲染么。然而,其中其实还是有一点细节可以考究一下的,我们一起来好好看看。
JS
阻塞 DOM
解析首先我们需要一个新的JS
文件名为blok.js
,内容如下:
const arr = []; for (let i = 0; i < 10000000; i++) { arr.push(i); arr.splice(i % 3, i % 7, i % 5); } const div = document.querySelector('div'); console.log(div);
其实那个数组操作时没意义的,只是为了让这个JS
文件多花执行时间而已。之后把这个文件插入头部,浏览器跑一下。
结果估计大家也能想象得到,浏览器转圈圈一会,这过程中不会有任何东西出现。之后打印出null
,再出现一个浅绿色的div
。现象就足以说明JS
阻塞 DOM
解析了。其实原因也很好理解,浏览器并不知道脚本的内容是什么,如果先行解析下面的DOM
,万一脚本内全删了后面的DOM
,浏览器就白干活了。更别谈丧心病狂的document.write
。浏览器无法预估里面的内容,那就干脆全部停住,等脚本执行完再干活就好了。
对此的优化其实也很显而易见,具体分为两类。如果JS
文件体积太大,同时你确定没必要阻塞DOM
解析的话,不妨按需要加上defer
或者async
属性,此时脚本下载的过程中是不会阻塞DOM
解析的。
而如果是文件执行时间太长,不妨分拆一下代码,不用立即执行的代码,可以使用一下以前的黑科技:setTimeout()
。当然,现代的浏览器很聪明,它会“偷看”之后的DOM
内容,碰到如2cdf5bf648cf2f33323966d7f58a7f3f
、3f1c4e4b6b16bbbd69b2ee476dc4f83a
和a1f02c36ba31691bcfe87b2722de723b
等标签时,它会帮助我们先行下载里面的资源,不会傻等到解析到那里时才下载。
3f1c4e4b6b16bbbd69b2ee476dc4f83a
标签时,会触发页面渲染这个细节可能不少看官大人并不清楚,其实这才是解释上面为何JS
执行会等待CSS
下载的原因。先上例子,HTML
内body
的结构如下:
<body> <div></div> <script src="/js/sleep3000-logDiv.js"></script> <style> div { background: lightgrey; } </style> <script src="/js/sleep5000-logDiv.js"></script> <link rel="stylesheet" href="/css/common.css"> </body>
这个例子也是很极端的例子,但不妨碍它透露给我们很多重要的信息。想象一下,页面会怎样呢?
答案是先浅绿色,再浅灰色,最后浅蓝色。由此可见,每次碰到3f1c4e4b6b16bbbd69b2ee476dc4f83a
标签时,浏览器都会渲染一次页面。这是基于同样的理由,浏览器不知道脚本的内容,因而碰到脚本时,只好先渲染页面,确保脚本能获取到最新的DOM
元素信息,尽管脚本可能不需要这些信息。
综上所述,我们得出这样的结论:
CSS
blockiert nicht das Parsen von DOM
, aber es blockiert das Rendern von DOM
. CSS
不会阻塞 DOM
的解析,但会阻塞 DOM
渲染。JS
阻塞 DOM
解析,但浏览器会"偷看"DOM
,预先下载相关资源。3f1c4e4b6b16bbbd69b2ee476dc4f83a
且没有defer
或async
属性的 标签时,会触发页面渲染,因而如果前面CSS
资源尚未加载完毕时,浏览器会等待它加载完毕在执行脚本。所以,你现在明白为何3f1c4e4b6b16bbbd69b2ee476dc4f83a
最好放底部,2cdf5bf648cf2f33323966d7f58a7f3f
最好放头部,如果头部同时有3f1c4e4b6b16bbbd69b2ee476dc4f83a
与2cdf5bf648cf2f33323966d7f58a7f3f
的情况下,最好将3f1c4e4b6b16bbbd69b2ee476dc4f83a
放在2cdf5bf648cf2f33323966d7f58a7f3f
JS
blockiert das Parsen von DOM
, aber der Browser „spioniert“ DOM
und lädt zugehörige Ressourcen im Voraus herunter.
3f1c4e4b6b16bbbd69b2ee476dc4f83a
trifft und kein defer
- oder async
-Attribut hat, löst er das Rendern der Seite aus. Wenn also die vorherige CSS
-Ressource nicht geladen wurde, wartet der Browser darauf, dass sie geladen wird, bevor er das Skript ausführt. Jetzt verstehen Sie also, warum 3f1c4e4b6b16bbbd69b2ee476dc4f83a
am besten unten und 2cdf5bf648cf2f33323966d7f58a7f3f
am besten unten platziert wird Wenn der Kopf sowohl 3f1c4e4b6b16bbbd69b2ee476dc4f83a
als auch 2cdf5bf648cf2f33323966d7f58a7f3f
enthält, ist es am besten, 3f1c4e4b6b16bbbd69b2ee476dc4f83a
einzufügen < ;link>
Ist es oben?
Vielen Dank, dass Sie diesen Artikel gelesen haben. Wenn Sie eine andere oder bessere Meinung haben, können Sie mich gerne aufklären. Vielen Dank~Ursprüngliche Adresse: https://juejin.cn/post/6844903497599549453Programmiervideo🎜! ! 🎜
Das obige ist der detaillierte Inhalt vonLassen Sie uns darüber sprechen, wie CSS und JS das Parsen und Rendern von DOM blockieren. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!