前端每日一問--JS 和 CSS 阻塞問題

candice的前端發表於2018-11-23

面試的時候被問到一個問題: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秒前的瀏覽器效果

前端每日一問--JS 和 CSS 阻塞問題
開啟瀏覽器,yellow.js是5秒後下載完畢,此時js會阻塞後續 DOM 的解析和其它資源(如 CSS,JS 或圖片資源)的載入。所以此時瀏覽器只會顯示文字“第一行內容”。

開啟到5秒左右的瀏覽器效果

前端每日一問--JS 和 CSS 阻塞問題
此時yellow.js下載完成執行,瀏覽器的背景顏色就是yellow了。

開啟到5秒後到15秒左右的瀏覽器效果

前端每日一問--JS 和 CSS 阻塞問題

red.css是15秒左右下載完成,而blue.js是10秒左右下載完成,在瀏覽器中我們看到是這樣的效果:blue.js比red.css先下載完成,但是blue.js並沒有執行,等red.css載入完成後blue.js才會執行。這就符合了前面的規則二:css載入不會阻塞DOM樹的解析,不會阻塞其它資源(如圖片)的載入,CSS載入會阻塞DOM樹的渲染,也會阻塞 JS 檔案的執行。

最後瀏覽器效果:

前端每日一問--JS 和 CSS 阻塞問題

等green.css載入完畢後圖片才會顯示出來,也能說明CSS載入會阻塞DOM樹的渲染,但是不會阻塞DOM樹的解析

最後這裡說明下為什麼最後 body 的背景色沒有變成綠色:因為 js 定義的樣式在內聯樣式,優先順序高於在 CSS 檔案中定義的樣式,所以不是 green.css 沒有載入,而是沒有生效。看下圖就知道了:(green 和 red 樣式都被劃掉了)

前端每日一問--JS 和 CSS 阻塞問題

相關文章