前端每日一问--JS 和 CSS 阻塞问题

875 阅读3分钟

面试的时候被问到一个问题:js会不会阻塞浏览器渲染?css会不会阻塞浏览器渲染? 在网上也查了不少资料,现在自己总结下。

总结

总结一句话:js是全阻塞,css会阻塞js的执行,先抛出几条规则,然后再贴测试代码

  • JS 会阻塞后续 DOM 的解析和其它资源(如 CSS,JS 或图片资源)的加载。
  • css加载不会阻塞DOM树的解析,不会阻塞其它资源(如图片)的加载,CSS加载会阻塞DOM树的渲染,也会阻塞 JS 文件的执行。

新建一个index.js,用node启动一个简单的web server,访问地址就是:http://127.0.0.1:9000/,

index.js

const http = require('http')
const fs = require('fs')
const hostname = '127.0.0.1'
const port = 9000

http.createServer((req, res) => {
  if(req.url === "/") {
    fs.readFile("index.html", "utf-8", function(err, data) {
      res.writeHead(200, { 'Content-Type': 'text/html' })
      res.write(data)
      res.end()
    }) 
  } else if (req.url === "/yellow.js") {
	//延迟 5s
    fs.readFile("yellow.js", "utf-8", function(err, data) {
      res.writeHead(200, { 'Content-Type': 'text/plain' })
      setTimeout(function () {
        res.write(data)
        res.end()
      }, 5000)
    })
  } else if (req.url === "/blue.js") {
    //延迟 10s
    fs.readFile("blue.js", "utf-8", function(err, data) {
      res.writeHead(200, { 'Content-Type': 'text/plain' })
      setTimeout(function () {
        res.write(data)
        res.end()
      }, 10000)
    })
  } else if (req.url === "/red.css") {
    //延迟 15s
    fs.readFile("red.css", "utf-8", function(err, data) {
      res.writeHead(200, { 'Content-Type': 'text/css' })
      setTimeout(function () {
        res.write(data)
        res.end()
      }, 15000)
    })
  } else if (req.url === "/green.css") {
    //延迟 20s
    fs.readFile("green.css", "utf-8", function(err, data) {
      res.writeHead(200, { 'Content-Type': 'text/css' })
      setTimeout(function () {
        res.write(data)
        res.end()
      }, 20000)
    })
  }
}).listen(port, hostname, () => {
  console.log('the Server running at ' + hostname)
})

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="cache-control" content="no-cache,no-store, must-revalidate" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>测试浏览器渲染</title>
</head>
<body>
    <p>第一行内容</p>
    <script src="/yellow.js"></script>
    <p>第二行内容</p>
    <link rel="stylesheet" href="/red.css">
    <p>第三行内容</p>
    <script src="/blue.js"></script>
    <p>第四行内容</p>
    <link rel="stylesheet" href="/green.css">
    <img src="http://www.quanjing.com/image/2018image/homepage/3.jpg?v=8">
    <p>第五行内容</p>
</body>
</html>

yellow.js

document.body.style.cssText = "background: yellow !important"

blue.js

document.body.style.cssText = "background: blue !important"

red.css

body {
  background:red !important;
}

green.css

body {
  background: green !important;
}

这里说明下:yellow.js 和 blue.js 下载时间分别为 5s 和 10s,red.css 和 green.css 下载时间分别为 15s 和 20s。测试浏览器为谷歌刘浏览器,版本 70.0.3538.102(正式版本)(64 位)

来看看规则1:JS 会阻塞后续 DOM 的解析和其它资源(如 CSS,JS 或图片资源)的加载。上截图:

打开到5秒前的浏览器效果

打开浏览器,yellow.js是5秒后下载完毕,此时js会阻塞后续 DOM 的解析和其它资源(如 CSS,JS 或图片资源)的加载。所以此时浏览器只会显示文字“第一行内容”。

打开到5秒左右的浏览器效果

此时yellow.js下载完成执行,浏览器的背景颜色就是yellow了。

打开到5秒后到15秒左右的浏览器效果

red.css是15秒左右下载完成,而blue.js是10秒左右下载完成,在浏览器中我们看到是这样的效果:blue.js比red.css先下载完成,但是blue.js并没有执行,等red.css加载完成后blue.js才会执行。这就符合了前面的规则二:css加载不会阻塞DOM树的解析,不会阻塞其它资源(如图片)的加载,CSS加载会阻塞DOM树的渲染,也会阻塞 JS 文件的执行。

最后浏览器效果:

等green.css加载完毕后图片才会显示出来,也能说明CSS加载会阻塞DOM树的渲染,但是不会阻塞DOM树的解析

最后这里说明下为什么最后 body 的背景色没有变成绿色:因为 js 定义的样式在内联样式,优先级高于在 CSS 文件中定义的样式,所以不是 green.css 没有加载,而是没有生效。看下图就知道了:(green 和 red 样式都被划掉了)