当我们访问url到界面渲染出来,整个流程是非常复杂的,主要是以下步骤:
- url解析,判断是搜索的内容还是访问网站
- 访问网站判断是否存在DNS缓存,如果没有缓存则解析DNS,获取IP
- 进行http(s)连接,3次握手
- 请求资源,通过content_type判断资源类型,如果是html文件,则网络进程,渲染进程开始启动
- 解析html生成dom树,遇到css文件通过预解析线程进行下载和解析css文件,解析css文件完成后交给主渲染线程生成cssom树(浏览器的默认样式,自定义的样式都会在这里,确保每个属性都有值),遇到js文件会阻塞dom树解析,先下载并执行js文件。
- 样式计算,遍历dom树,遍历每个节点,生成带有样式的dom树
- layout,遍历dom树,获取每个节点的几何信息,例如宽高,相对位置等;dom树和布局树往往是不一致的,layout树会删除一些dispaly none的节点。生成layout的过程中一些新增一些匿名盒子,比如内容必须在行盒子内,行盒和块盒不能相邻。
- 分层,浏览器会根据层叠上下文进行分层,防止每次变更整个界面全部更新
- 绘制,生成绘制指令集(用于描述界面怎么画出来),然后交给合成线程
- 分块,合成线程在线程池中取几个分块器线程一起帮忙,把每一层分成多个小块
- 光栅化,分块完成后,每个块变成位图(这部分会用到gpu加速),优先处理窗口可视范围的块
- 合成线程将位图信息交给gpu进程,再交给显卡来画界面
既然整个流程清楚了,那么涉及前端工程的一些优化也和上面这些步骤息息相关
- dns预解析,dns-prefetch
- http升级成https,增加最大并发请求数
- 可以css放在顶部,先提供给用户一些loading页样式,正常script标签请求执行会阻塞html解析,可以js文件放在底部,或通过defer或者async优化
- defer 请求异步进行,不会堵塞解析html,下载完成后等待dom解析完成再执行
- async 请求会异步进行,不会堵塞解析html,等待下载完成后暂停dom解析,执行js
- 充分利用浏览器缓存
- 前端打包工具,压缩文件体积
- JavaScript:UglifyPlugin
- CSS :MiniCssExtractPlugin
- HTML:HtmlWebpackPlugin
- gzip:compression-webpack-plugin
- 图片懒加载,或者改变图片格式webp
- 减少回流,重绘。比如合成多次dom操作,将频繁操作的内容脱离文档流或者分层
- js文件拆分,懒加载
- 代码优化( if else 和 选择器)
- web worker线程处理纯异步逻辑
- css3的gpu加速,例如transform的本质是位图矩阵信息变化,发生在合成线程,所以效率高。