浏览器解析过程,进程和线程,性能优化
【摘要】 页面加载顺序// 3window.onload = function () { // 触发条件:所有资源都加载完成(包含DOM TREE/CSS/图片等资源) console.log(document.getElementById('box'));};// 2window.addEventListener('DOMContentLoaded', function () { ...
页面加载顺序
// 3
window.onload = function () {
// 触发条件:所有资源都加载完成(包含DOM TREE/CSS/图片等资源)
console.log(document.getElementById('box'));
};
// 2
window.addEventListener('DOMContentLoaded', function () {
// 触发条件:DOM TREE加载完成即可
console.log(document.getElementById('box'));
});
// 1
setTimeout(() => {
console.log(document.getElementById('box'));
}, 0);
一个页面从服务器访问回来后,浏览器拿到页面源代码,之后做的一些事情
1.生成 DOM TREE =>对HTML的处理
基于HTTP获取的是流文件(进制编码)
把进制编码编译为具体的字符
按照TOKEN进行解析(词法解析)
生层具体的节点(元素节点/文本节点...)
按照相互的嵌套关系生成一个DOM树(节点树)
2.生成 CSSOM TREE =>对CSS的处理
3.生成 RENDER TREE (渲染树)
DOM TREE + CSSOM TREE = RENDER TREE
对于开始设置为display:none样式的元素是不会在渲染树中生成的(开始加载页面这些元素是不进行渲染的)
4.布局/回流/重排 Layout
按照渲染树计算出每一个元素在视口中的位置和大小
5.分层
按照计算出来的样式进行分层
定位
设置透明度 RGBA
设置滤镜
文本超过盒子大小,我们把它裁切了
...
单独计算每一层的绘制列表(具体怎么绘制)
---------->以上的操作都是交给“GUI渲染线程”来完成的
6.绘制/重绘 Painting
把生成的绘制列表提交给“合成线程”
“合成线程”进行我们最后的绘制,呈现在浏览器的页面上
进程和线程
进程:一个程序(浏览器新建一个页卡就是一个进程) 【工厂】
线程:一个进程中可能会包含多个线程,每个线程同时可以做一件事情 【工人】
真正的同时做多件事情必须依赖多线程(浏览器是多线程的)
但是JS本身是单线程的 [因为浏览器本身只分配一个线程 “GUI渲染线程” 运行JS代码]
JS本身从本质来讲是不能同时做多件事情的
同步:上一件事情完成,再去做下一件事情
异步:上一件事情没有完成(我们把它做一些特殊处理),下一件事情继续执行 [但是绝对不是JS可以同时处理两个事情]
浏览器生层DOM TREE/CSSOM TREE...的过程也是单线程的“GUI渲染线程”(配合浏览器的多线程去完成一些事情,例如:资源请求就是利用的就是浏览器的HTTP网络线程去做的)
浏览器具体的解析过程 “GUI渲染线程”
1. 自上而下解析完所有的HTML标签/各种节点后,DOM TREE就生成了
2. 但是过程中还会遇到一些比较特殊的
link href='xxx.css' 外链式
=>浏览器会分配一个新的HTTP网络线程去加载资源文件
=>不会阻碍DOM树的渲染
<style> ... </style> 内嵌式
=>不用去请求新的资源文件了,但是此时样式还没有处理,浏览器会做一个记录,它会等待所有的CSS资源加载回来之后,按照先后顺序依次渲染CSS,从而生成CSSOM树
@import 'xxx.css' 导入式
=>虽然也是分配网络HTTP线程去加载资源文件
=>但是此时GUI渲染线程会被阻塞掉[阻碍DOM树渲染](只有等资源加载回来,才会继续渲染DOM)
遇到script 内嵌js代码的
=>立即执行JS(阻碍DOM TREE的渲染)
遇到script 外链js代码的
=>阻碍DOM TREE的渲染,同时分配一个HTTP线程去加载资源文件
=>加载回来后立即执行JS
=>如果JS中没有采用异步,直接获取DOM元素,而DOM元素此时还没有渲染,JS是获取不到的
遇到img
=>老版本浏览器会阻碍DOM渲染
=>新版浏览器虽然不会阻碍DOM渲染,但是图片资源的请求会占用HTTP线程(浏览器同时只能开6~7个HTTP线程,这样图片/音视频资源加载本来就会慢一些,会影响其他资源link/script等的加载)
=>图片资源的渲染也是比一般资源耗时间的,也会拖累页面的渲染速度
...
性能优化
1. 不用@import
2. link放到HEAD中(尽可能提前去加载资源文件,这样等DOM树渲染完,资源可能也加载回来了): 当代浏览器的机制越发完善,Webkit浏览器预测解析:chrome的预加载扫描器html-preload-scanner通过扫描节点中的 “src” , “link”等属性,找到外部连接资源后进行预加载,避免了资源加载的等待时间,同样实现了提前加载以及加载和执行分离
3. 如果CSS代码比较少,尽可能使用内嵌式,可以减少HTTP请求;但是如果样式比较多,采用内嵌式,第一次加载HTML都会浪费很长的时间,这样还不如基于link分开加载;移动端开发都是内嵌有先(当然也要考虑CSS代码量的);
4. 减少DOM或者减少DOM的层级嵌套,以及标签语义化...(当代前端开发,开始只把首屏的结构/内容写出来,渲染只是首屏的,当首屏加载完,页面滚动的时候,再基于JS创建其他屏幕的结构和内容 => 骨架屏/SSR =>客户端骨架屏,开始首屏结构都没有,只有一个loading或者占位图而已...)
5. 把script放到页面的底部(先渲染DOM TREE,再执行JS,也可以获取到DOM元素了),也可以基于事件DOMContentLoaded/load等到结构加载完再去获取DOM元素
6. async / defer 给script设置的属性
=>async是开辟HTTP线程加载资源文件,此时DOM TREE继续,但是资源文件一但加载回来,停止DOM TREE,先执行JS代码(不考虑JS引入顺序,谁先加载回来谁先执行)
=>defer也是开辟HTTP线程加载资源文件,即使资源文件加载回来,也会等待DOM树渲染完,然后按照JS的导入顺序依次执行JS(不兼容低版本浏览器)
7. 图片合并(Sripte)/ BASE64(好用但是慎用) / iconfont(CSS绘制) / svg
=> 图片的懒加载
....
8. CRP(critical rendering path)浏览器关键路径节点优化
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)