? 如果做性能優(yōu)化,一定會(huì)想當(dāng)?shù)囊粋€(gè)優(yōu)化點(diǎn)就是script標(biāo)簽和link標(biāo)簽要放置的位置,當(dāng)然大部分的觀點(diǎn)都是script標(biāo)簽放到</body>之前,link標(biāo)簽放到title中;或者是配" />

国产成人精品无码青草_亚洲国产美女精品久久久久∴_欧美人与鲁交大毛片免费_国产果冻豆传媒麻婆精东

15158846557 在線咨詢 在線咨詢
15158846557 在線咨詢
所在位置: 首頁(yè) > 營(yíng)銷資訊 > 網(wǎng)站運(yùn)營(yíng) > 【瀏覽器渲染】這是一份關(guān)于script和style的實(shí)驗(yàn)報(bào)告

【瀏覽器渲染】這是一份關(guān)于script和style的實(shí)驗(yàn)報(bào)告

時(shí)間:2023-10-06 19:06:02 | 來源:網(wǎng)站運(yùn)營(yíng)

時(shí)間:2023-10-06 19:06:02 來源:網(wǎng)站運(yùn)營(yíng)

【瀏覽器渲染】這是一份關(guān)于script和style的實(shí)驗(yàn)報(bào)告:

? 如果做性能優(yōu)化,一定會(huì)想當(dāng)?shù)囊粋€(gè)優(yōu)化點(diǎn)就是script標(biāo)簽和link標(biāo)簽要放置的位置,當(dāng)然大部分的觀點(diǎn)都是script標(biāo)簽放到</body>之前,link標(biāo)簽放到title中;或者是配合async、defer、preload、prefech使用,當(dāng)然目的只有一個(gè):讓頁(yè)面盡可能快的展示在用戶面前。下面僅僅會(huì)討論瀏覽器獲取到HTML文件后的部分。
?

瀏覽器渲染過程

? 瀏覽器獲取到HTML文件后,開始渲染工作。這里以webkit引擎為例。
  1. 解析html產(chǎn)生DOM樹
  2. 解析css樣式產(chǎn)生CSSOM樹
  3. DOM樹和CSSOM樹合成渲染樹(RenderTree)
  4. 布局RenderTree(layout):確定在屏幕中位置
  5. 繪制(paint)
  6. 合成(composite): 將多個(gè)圖層合并
為了提高用戶體驗(yàn),渲染引擎會(huì)盡快的把結(jié)果渲染給用戶,它不會(huì)等待所有的html都解析完成才渲染,它會(huì)在網(wǎng)絡(luò)層獲取文檔的同時(shí),將已經(jīng)接收的局部渲染到頁(yè)面中(實(shí)驗(yàn)3將會(huì)證明這一說法)
?

實(shí)驗(yàn)環(huán)境準(zhǔn)備

1. 模擬服務(wù)端: 所需要的文件hand.js、style.css、server.js

// server.jsconst http = require('http');const fs = require('fs')http.createServer(function (request, response) { if (request.url === '/index.html') { fs.readFile('./index.html', (err, data) => { response.setHeader('Content-Type', 'text/html'); if (!err) { response.end(data); }else { response.end('html not found'); } }) } if (request.url === '/hand.js') { fs.readFile('./static/hand.js', (err, data) => { response.setHeader('Content-Type', 'text/javascript'); if (!err) { setTimeout(() => { response.end(data); }, 100); }else { response.end('html not found'); } }) } if (request.url === '/style.css') { fs.readFile('./static/style.css', (err, data) => { response.setHeader('Content-Type', 'text/css'); if (!err) { setTimeout(() => { response.end(data); }, 1000); }else { response.end('html not found'); } }) } if (request.url === '/favicon.ico') { response.end() }}).listen(8888);console.log('port 8888')// hand.js(無內(nèi)容)// style.cssp { color: red;}

前端部分

<!--index.html--><!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"></head><body> <p>我是第一個(gè)</p> <p>我是第二個(gè)</p> <p>我是第三個(gè)</p></body></html>

備注:以下的實(shí)驗(yàn)圖片中,請(qǐng)忽略掉實(shí)驗(yàn)1、3、8、9、10報(bào)告的第一個(gè)渲染幀(因?yàn)闉g覽器會(huì)紀(jì)錄頁(yè)面刷新前的一個(gè)渲染幀)

script標(biāo)簽

為什么script標(biāo)簽會(huì)阻塞頁(yè)面的渲染?

? javascript能操作dom樹,瀏覽器卻不知道腳本中是否有操作dom的代碼(比如document.write等),所以以最壞的打算來處理:停止dom的解析,所以更準(zhǔn)確的說是「script標(biāo)簽會(huì)阻止dom的解析」
解釋幾個(gè)下面實(shí)驗(yàn)用到的名詞(以下解釋均來源于MDN)
  1. DCL(DOMContentLoaded): 當(dāng)HTML被完全加載以及「解析」時(shí),DOMContentLoaded事件會(huì)被觸發(fā),而不必等待樣式表,圖片或者子框架完成加載
  2. L(load): 當(dāng)整個(gè)頁(yè)面及所有依賴資源如「樣式表和圖片都已完成加載」時(shí),將觸發(fā)load事件
  3. FP(first paint): 頁(yè)面導(dǎo)航與瀏覽器將該網(wǎng)頁(yè)的第一個(gè)像素「渲染」到屏幕上
以上名詞縮寫將會(huì)出現(xiàn)在下面的實(shí)驗(yàn)截圖中
?

實(shí)驗(yàn)1: 內(nèi)聯(lián)script標(biāo)簽

<head> <meta charset="UTF-8"> <script> var a = 0 for (let i = 0; i< 1000000000; i++) { a += 1 } </script></head><body> <p>我是第一個(gè)</p></body><head> <meta charset="UTF-8"></head><body> <p>我是第一個(gè)</p> <script> var a = 0 for (let i = 0; i< 1000000000; i++) { a += 1 } </script></body>

實(shí)驗(yàn)2: 內(nèi)聯(lián)script標(biāo)簽(換一種實(shí)現(xiàn)方式)

<head> <meta charset="UTF-8"></head><body> <script> const node = document.getElementsByTagName('p') console.log(node[0]) // undefined </script> <p>我是第一個(gè)</p></body><head> <meta charset="UTF-8"></head><body> <p>我是第一個(gè)</p> <script> const node = document.getElementsByTagName('p') console.log(node[0]) // <p>我是第一個(gè)</p> </script></body>

實(shí)驗(yàn)3: 外部引入的script標(biāo)簽放在title中

<html lang="en"><head> <meta charset="UTF-8"> <script src="http://localhost:8888/hand.js"></script></head><body> <p>我是第一個(gè)</p></body></html>

實(shí)驗(yàn)4: 外部引入的script標(biāo)簽放在body中

<html lang="en"><head> <meta charset="UTF-8"></head><body> <p>我是第一個(gè)</p> <p>我是第二個(gè)</p> <script src="http://localhost:8888/hand.js"></script> <p>我是第三個(gè)</p></body></html>

實(shí)驗(yàn)5: 外部引入的script標(biāo)簽放在</body>前

<html lang="en"><head> <meta charset="UTF-8"></head><body> <p>我是第一個(gè)</p> <p>我是第二個(gè)</p> <p>我是第三個(gè)</p> <script src="http://localhost:8888/hand.js"></script></body></html>

實(shí)驗(yàn)6: 外部引入的script標(biāo)簽放在title中,并且加入async參數(shù)

<head> <meta charset="UTF-8"> <script src="http://localhost:8888/hand.js" async></script></head><body> <p>我是第一個(gè)</p> <p>我是第二個(gè)</p> <p>我是第三個(gè)</p></body>

實(shí)驗(yàn)7: 外部引入的script標(biāo)簽放在title中,并且加入defer參數(shù)

<head> <meta charset="UTF-8"> <script src="http://localhost:8888/hand.js" defer></script></head><body> <p>我是第一個(gè)</p> <p>我是第二個(gè)</p> <p>我是第三個(gè)</p></body>
? 總結(jié):
  1. 內(nèi)聯(lián)的script會(huì)阻塞dom解析,并且不會(huì)使之前解析過的dom預(yù)先渲染
  2. 外部引入的script標(biāo)簽會(huì)阻塞dom的解析,但是之前解析過的dom瀏覽器會(huì)先渲染
  3. 加入async和defer可以強(qiáng)制script標(biāo)簽不去阻塞dom的解析
  4. defer會(huì)阻塞DOMContentLoaded事件,而async不會(huì)
?

link標(biāo)簽引入的css

? 我們一般用link標(biāo)簽引用css樣式文件。如果你看過vue打包后的文件,會(huì)發(fā)現(xiàn)它的一些腳本文件也是通過link標(biāo)簽引入的。不過我們這篇文章中不對(duì)其進(jìn)行討論。「樣式文件不會(huì)阻塞dom的解析,但是會(huì)阻塞dom的渲染」,接下來用幾個(gè)實(shí)驗(yàn)來證明css是如何阻塞dom的渲染的
?

實(shí)驗(yàn)8: link標(biāo)簽引入的css放到title中

<head> <meta charset="UTF-8"> <link rel="stylesheet" href="http://localhost:8888/style.css"></head><body> <p>我是第一個(gè)</p> <p>我是第二個(gè)</p> <p>我是第三個(gè)</p></body>

實(shí)驗(yàn)8: link標(biāo)簽引入的css放到</body>前

<head> <meta charset="UTF-8"></head><body> <p>我是第一個(gè)</p> <p>我是第二個(gè)</p> <p>我是第三個(gè)</p> <link rel="stylesheet" href="http://localhost:8888/style.css"></body>
? 總結(jié):
  1. css不會(huì)阻塞dom的解析,但是會(huì)阻塞dom的渲染
  2. css若放在body末尾,頁(yè)面會(huì)從無樣式到有樣式的過渡,會(huì)讓用戶體驗(yàn)很差
?

script與css的標(biāo)簽同時(shí)存在

? 一個(gè)靜態(tài)文件中一定會(huì)同時(shí)存在script和link標(biāo)簽的情況,它們之間又是互相影響的?
?

實(shí)驗(yàn)9: link與script都放在title中,且link放在script之前

<html lang="en"><head> <meta charset="UTF-8"> <link rel="stylesheet" href="http://localhost:8888/style.css" /> <script src="http://localhost:8888/hand.js"></script></head><body> <p>我是第一個(gè)</p> <p>我是第二個(gè)</p> <p>我是第三個(gè)</p></body>

實(shí)驗(yàn)10: link與script都放在title中,且link放在script之后

<html lang="en"><head> <meta charset="UTF-8"> <script src="http://localhost:8888/hand.js"></script> <link rel="stylesheet" href="http://localhost:8888/style.css" /></head><body> <p>我是第一個(gè)</p> <p>我是第二個(gè)</p> <p>我是第三個(gè)</p></body>

實(shí)驗(yàn)11: link在title中,script放到</body>前(情況1)

<html lang="en"><head> <meta charset="UTF-8"> <link rel="stylesheet" href="http://localhost:8888/style.css" /></head><body> <p>我是第一個(gè)</p> <p>我是第二個(gè)</p> <p>我是第三個(gè)</p> <script src="http://localhost:8888/hand.js"></script></body>

實(shí)驗(yàn)12: link在title中,script放到</body>前(情況2)

// 讓我們修改一下serve.js文件中的js文件和css的返回時(shí)間if (request.url === '/hand.js') { fs.readFile('./static/hand.js', (err, data) => { response.setHeader('Content-Type', 'text/javascript'); if (!err) { setTimeout(() => { response.end(data); }, 1000); }else { response.end('html not found'); } }) } if (request.url === '/style.css') { fs.readFile('./static/style.css', (err, data) => { response.setHeader('Content-Type', 'text/css'); if (!err) { setTimeout(() => { response.end(data); }, 100); }else { response.end('html not found'); } }) }<html lang="en"><head> <meta charset="UTF-8"> <link rel="stylesheet" href="http://localhost:8888/style.css" /></head><body> <p>我是第一個(gè)</p> <p>我是第二個(gè)</p> <p>我是第三個(gè)</p> <script src="http://localhost:8888/hand.js"></script></body>
? 總結(jié):
  1. css不會(huì)阻塞外部腳本的加載,但是會(huì)阻塞js的執(zhí)行(GUI線程和js線程互斥,因?yàn)橛锌赡躩s會(huì)操作 CSS)
  2. 最佳實(shí)踐:script標(biāo)簽放在body的末尾,style標(biāo)簽放在body之前
?

參考文檔

關(guān)鍵詞:報(bào)告,實(shí)驗(yàn),渲染,瀏覽

74
73
25
news

版權(quán)所有? 億企邦 1997-2025 保留一切法律許可權(quán)利。

為了最佳展示效果,本站不支持IE9及以下版本的瀏覽器,建議您使用谷歌Chrome瀏覽器。 點(diǎn)擊下載Chrome瀏覽器
關(guān)閉