原本只是想分享Network的一些内容,结果到DOMContentLoaded的时候给卡住了,网上很多强调css不会阻塞DOM解析,可以说对又可以说不对。
在MDN上面给出了DOMContentLoaded的解释:
当初始的 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发,而无需等待样式表、图像和子框架的完全加载。
也给出了模拟css的php,说是link要是置于script之后就会立即打印。于是我用node自己模拟了一个css,结果却不一样。
node模拟css:
const http=require('http');
http.createServer(function(requset,response){
response.setHeader('Access-Control-Allow-Credentials', 'true');
response.setHeader('Access-Control-Allow-Origin', '*');
setTimeout(() => {
response.end('#test{color:red}');
}, 3000);
}).listen(3001);
console.log('run port 3001')
接着就是页面代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>DOMContentLoaded</title>
<link rel="stylesheet" href="http://192.168.9.110:3001/a.css">
</head>
<body>
<script></script>
</body>
</html>
我测试了几种情况,分别如下:
第一种,link在script之前或者之后,并且script有内容,包括一个回车或者一个空格,DOMContentLoaded和Load的时间一样:
这种情况表示css阻塞了DOM的解析。
第二种,我把link放到script之前,script里面没有任何内容,DOMContentLoaded比Load的时间差很多:
第三种,我把link放到script之后,script里面没有任何内容,DOMContentLoaded和Load的时间一样:
这边补充一下,script引入的也是一样的。至于其他情况async或者defer就没测试了,结果和现在网上说的各种解析好像都不一样。并不是js有操作样式才会使得css阻塞。
大概得出的结论:
浏览器解析DOM的时候,如果没有任何script的脚本,这边指的是没有任何内容,可以有script标签,css是不会阻塞DOM的解析,也符合常见的说法。如果有script脚本,只要一个空格或者一个换行,浏览器没法判断脚本里是否访问了元素的样式,所以只要出现脚本,全部阻塞处理。
于是出现了一个问题,我们经常做的把link放到script前面,到底有用还是没用呢?于是测试了一下:
<p id="test">test</p>
<script>
console.log(getComputedStyle(document.getElementById('test'), null).color);
document.addEventListener('DOMContentLoaded',function(){
console.log(getComputedStyle(document.getElementById('test'), null).color);
});
</script>
分别把link放到这段代码之前和之后,放到之前,会等css加载完成打印,两个打印都是rgb(255, 0, 0),放到之后,第一个会打印rgb(0, 0, 0),第二个会打印rgb(255, 0, 0)。
最后想说,我们开发的时候几乎不可能不涉及js脚本,但是,把link放到head里面,尽可能早的加载css,也算是优化。当然,也是很想知道DOMContentLoaded和css阻塞的具体原因,希望有研究V8源码的大佬可以给解答解答。
coding个人笔记 公众号