この記事では、CSS と JS が DOM の解析とレンダリングをブロックする原理を紹介します。一定の参考値があるので、困っている友達が参考になれば幸いです。
#こんにちは~ 読者の皆様、こんにちは。誰もが聞いたことがあると思いますが、CSS
を先頭に、JS
を最後に配置すると、ページのパフォーマンスが向上します。しかし、なぜでしょうか?検討しましたか?ずっと前から知ってたけど、なぜかわからなかった、もちろん試験のために暗記するのはいいけど、実際に応用するとめちゃくちゃになってしまう。そこで、洗い(王)、心(陽)、皮(ブ)、顔(ラオ)を洗い、最近の結果をまとめます。
この記事は主に初心者向けです。結論を直接確認したい場合は、一番下までスクロールしてください~
ファイルの読み取りに関連しているため、それは確かです。サーバーが必要な場合は、すべてのファイルを 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 については、先頭のパフォーマンスに
<link> タグが配置されていることを誰もが知っている必要があります。少し高くなりますが、
<script> と
<link> が同時に先頭にある場合、
<script> が先頭にあることを知っている人は少なくなります。
が一番上にある可能性があります。どうしてこれなの? CSS
が DOM
に与える影響を見てみましょう。
CSS
は DOM
注意!ここで話しているのは DOM
の解析です。証明例は次のとおりです。最初に <script defer src="/js/logDiv.js"></script># を挿入します。ヘッダーの ## 、
JS ファイルの内容は次のとおりです:
const div = document.querySelector('div'); console.log(div);
defer 属性 誰もがよく知っていると思いますが、
MDNこれの説明は、ドキュメントの解析が完了した後、DOMContentLoaded イベントがトリガーされる前に、ブラウザー スクリプトが実行されることを通知するためです。このプロパティを設定すると、DOM が解析された直後に
div が確実に出力されます。
を
HTML ファイルの任意の位置に挿入します。ブラウザを開くと、
DOM ノード
div が最初に出力され、約 3 秒後に水色の
div がレンダリングされることがわかります。これは、
CSS が
DOM の解析をブロックしないことを証明しています。
CSS のダウンロードには 3 秒かかりますが、ブラウザはこのプロセス中に愚かに待機しません。
CSSダウンロード後、
DOM が解析されます。
DOM を解析して
DOM Tree を生成し、
CSS を結合して
CSS Tree# を生成します。 ## 、最後に render Tree
を形成し、ページをレンダリングします。このプロセスでは CSS
が DOM Tree
に影響を与えないことがわかります。そのため、DOM
の解析をブロックする必要はありません。ただし、DOM Tree
と CSS Tree
は render Tree
に結合されるため、CSS
はページのレンダリングをブロックしますか?
実際、この例では、 がブロックしない場合にこの点を説明しました。ページがレンダリングをブロックすると、ブラウザは CSS
ファイルがダウンロードされる前に薄緑色の div
を表示し、その後水色に変わります。ブラウザのこの戦略は実際には非常に賢明です。この戦略がなければ、ページは最初は元の外観を表示し、CSS
がダウンロードされた後、その外観が突然変わることを想像してください。ユーザーエクスペリエンスは非常に悪く、レンダリングにはコストがかかります。 したがって、パフォーマンスとユーザー エクスペリエンスを考慮して、ブラウザーはレンダリングの数を減らそうとするため、
は当然ページのレンダリングをブロックします。 ただし、状況は常に奇妙です。この例を見てください。
ヘッダー構造は次のとおりです: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;"><header>
<link rel="stylesheet" href="/css/sleep3000-common.css">
<script src="/js/logDiv.js"></script>
</header></pre><div class="contentsignin">ログイン後にコピー</div></div>
しかし、これがどのような結果を生み出すか考えてください。
答案是浏览器会转圈圈三秒,但此过程中不会打印任何东西,之后呈现出一个浅蓝色的div
,再打印出null
。结果好像是CSS
不单阻塞了页面渲染,还阻塞了DOM
的解析啊!稍等,在你打算掀桌子疯狂吐槽我之前,请先思考一下是什么阻塞了DOM
的解析,刚才已经证明了CSS
是不会阻塞的,那么阻塞了页面解析其实是JS
!但明明JS
的代码如此简单,肯定不会阻塞这么久,那就是JS
在等待CSS
的下载,这是为什么呢?
仔细思考一下,其实这样做是有道理的,如果脚本的内容是获取元素的样式,宽高等CSS
控制的属性,浏览器是需要计算的,也就是依赖于CSS
。浏览器也无法感知脚本内容到底是什么,为避免样式获取,因而只好等前面所有的样式下载完后,再执行JS
。因而造成了之前例子的情况。
所以,看官大人明白为何<script>
与<link>
同时在头部的话,<script>
在上可能会更好了么?之所以是可能,是因为如果<link>
的内容下载更快的话,是没影响的,但反过来的话,JS
就要等待了,然而这些等待的时间是完全不必要的。
JS
,也就是<script>
标签,估计大家都很熟悉了,不就是阻塞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
内容,碰到如<link>
、<script>
和<img>
等标签时,它会帮助我们先行下载里面的资源,不会傻等到解析到那里时才下载。
<script>
标签时,会触发页面渲染这个细节可能不少看官大人并不清楚,其实这才是解释上面为何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>
这个例子也是很极端的例子,但不妨碍它透露给我们很多重要的信息。想象一下,页面会怎样呢?
答案是先浅绿色,再浅灰色,最后浅蓝色。由此可见,每次碰到<script>
标签时,浏览器都会渲染一次页面。这是基于同样的理由,浏览器不知道脚本的内容,因而碰到脚本时,只好先渲染页面,确保脚本能获取到最新的DOM
元素信息,尽管脚本可能不需要这些信息。
综上所述,我们得出这样的结论:
CSS
は DOM
の解析をブロックしませんが、DOM
のレンダリングをブロックします。 JS
DOM
の解析をブロックしますが、ブラウザは DOM
を「覗き見」し、関連リソースを事前にダウンロードします。 <script>
を持ち、defer
または async
属性を持たないタグを検出すると、ページのレンダリングがトリガーされます。前の CSS
リソースがロードされていない場合、ブラウザはリソースがロードされるのを待ってからスクリプトを実行します。 これで、<script>
を一番下に配置するのが最適であり、<link>
を配置するのが最適である理由がわかりました。 <script>
と <link>
がある場合、# に <script>
を入れるのが最善です。 ##<link>上ですか?
元のアドレス: https://juejin.cn/post/6844903497599549453プログラミング関連の知識の詳細については、こちらをご覧ください:
以上がCSS と JS が DOM の解析とレンダリングをどのようにブロックするかについて話しましょうの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。