15158846557 在线咨询 在线咨询
15158846557 在线咨询
所在位置: 首页 > 营销资讯 > 网站运营 > 【浏览器渲染】这是一份关于script和style的实验报告

【浏览器渲染】这是一份关于script和style的实验报告

时间:2023-10-06 19:06:02 | 来源:网站运营

时间:2023-10-06 19:06:02 来源:网站运营

【浏览器渲染】这是一份关于script和style的实验报告:

❝ 如果做性能优化,一定会想当的一个优化点就是script标签和link标签要放置的位置,当然大部分的观点都是script标签放到</body>之前,link标签放到title中;或者是配合async、defer、preload、prefech使用,当然目的只有一个:让页面尽可能快的展示在用户面前。下面仅仅会讨论浏览器获取到HTML文件后的部分。

浏览器渲染过程

❝ 浏览器获取到HTML文件后,开始渲染工作。这里以webkit引擎为例。
  1. 解析html产生DOM树
  2. 解析css样式产生CSSOM树
  3. DOM树和CSSOM树合成渲染树(RenderTree)
  4. 布局RenderTree(layout):确定在屏幕中位置
  5. 绘制(paint)
  6. 合成(composite): 将多个图层合并
为了提高用户体验,渲染引擎会尽快的把结果渲染给用户,它不会等待所有的html都解析完成才渲染,它会在网络层获取文档的同时,将已经接收的局部渲染到页面中(实验3将会证明这一说法)


实验环境准备

1. 模拟服务端: 所需要的文件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(无内容)// style.cssp { color: red;}

前端部分

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

备注:以下的实验图片中,请忽略掉实验1、3、8、9、10报告的第一个渲染帧(因为浏览器会纪录页面刷新前的一个渲染帧)

script标签

为什么script标签会阻塞页面的渲染?

❝ javascript能操作dom树,浏览器却不知道脚本中是否有操作dom的代码(比如document.write等),所以以最坏的打算来处理:停止dom的解析,所以更准确的说是「script标签会阻止dom的解析」
解释几个下面实验用到的名词(以下解释均来源于MDN)
  1. DCL(DOMContentLoaded): 当HTML被完全加载以及「解析」时,DOMContentLoaded事件会被触发,而不必等待样式表,图片或者子框架完成加载
  2. L(load): 当整个页面及所有依赖资源如「样式表和图片都已完成加载」时,将触发load事件
  3. FP(first paint): 页面导航与浏览器将该网页的第一个像素「渲染」到屏幕上
以上名词缩写将会出现在下面的实验截图中


实验1: 内联script标签

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

实验2: 内联script标签(换一种实现方式)

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

实验3: 外部引入的script标签放在title中

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

实验4: 外部引入的script标签放在body中

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

实验5: 外部引入的script标签放在</body>前

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

实验6: 外部引入的script标签放在title中,并且加入async参数

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

实验7: 外部引入的script标签放在title中,并且加入defer参数

<head> <meta charset="UTF-8"> <script src="http://localhost:8888/hand.js" defer></script></head><body> <p>我是第一个</p> <p>我是第二个</p> <p>我是第三个</p></body>
❝ 总结:
  1. 内联的script会阻塞dom解析,并且不会使之前解析过的dom预先渲染
  2. 外部引入的script标签会阻塞dom的解析,但是之前解析过的dom浏览器会先渲染
  3. 加入async和defer可以强制script标签不去阻塞dom的解析
  4. defer会阻塞DOMContentLoaded事件,而async不会


link标签引入的css

❝ 我们一般用link标签引用css样式文件。如果你看过vue打包后的文件,会发现它的一些脚本文件也是通过link标签引入的。不过我们这篇文章中不对其进行讨论。「样式文件不会阻塞dom的解析,但是会阻塞dom的渲染」,接下来用几个实验来证明css是如何阻塞dom的渲染的

实验8: link标签引入的css放到title中

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

实验8: link标签引入的css放到</body>前

<head> <meta charset="UTF-8"></head><body> <p>我是第一个</p> <p>我是第二个</p> <p>我是第三个</p> <link rel="stylesheet" href="http://localhost:8888/style.css"></body>
❝ 总结:
  1. css不会阻塞dom的解析,但是会阻塞dom的渲染
  2. css若放在body末尾,页面会从无样式到有样式的过渡,会让用户体验很差


script与css的标签同时存在

❝ 一个静态文件中一定会同时存在script和link标签的情况,它们之间又是互相影响的?

实验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>我是第一个</p> <p>我是第二个</p> <p>我是第三个</p></body>

实验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>我是第一个</p> <p>我是第二个</p> <p>我是第三个</p></body>

实验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>我是第一个</p> <p>我是第二个</p> <p>我是第三个</p> <script src="http://localhost:8888/hand.js"></script></body>

实验12: link在title中,script放到</body>前(情况2)

// 让我们修改一下serve.js文件中的js文件和css的返回时间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>我是第一个</p> <p>我是第二个</p> <p>我是第三个</p> <script src="http://localhost:8888/hand.js"></script></body>
❝ 总结:
  1. css不会阻塞外部脚本的加载,但是会阻塞js的执行(GUI线程和js线程互斥,因为有可能js会操作 CSS)
  2. 最佳实践:script标签放在body的末尾,style标签放在body之前


参考文档

关键词:报告,实验,渲染,浏览

74
73
25
news

版权所有© 亿企邦 1997-2025 保留一切法律许可权利。

为了最佳展示效果,本站不支持IE9及以下版本的浏览器,建议您使用谷歌Chrome浏览器。 点击下载Chrome浏览器
关闭