浏览器渲染机制与优化

1.1 资源的请求和解析

请求是指资源获取,解析指的是代码的执行

  1. 客户端从服务器获取页面源代码
    1. 浏览器拿到源码之后开启 GUI 渲染进程,自上而下解析代码,最后绘制
    2. GUI自上而下渲染解析代码过程整体是同步的,但也会遇到异步行为
  2. CSS资源加载
    1. style 内嵌样式,GUI线程执行同步渲染行为
    2. link 外链样式,异步操作
      1. 开启 HTTP 网络请求线程
      2. 异步操作不会等到资源完全获取,GUI 线程会继续向下渲染
      3. GUI 线程将同步操作执行完成之后再处理基于 HTTP 网络请求回来的资源
    3. @import 导入样式(同步操作)
      1. 同步操作,开启一个新的网络线程去请求资源文件
      2. 和 link 相同点是它也会开启 HTTP请求去下载资源
      3. 和 link 不同点是它会阻塞 GUI 线程渲染,在资源回来之前渲染不会继续
  3. Javascript 资源
    1. 默认情况下 script 都是同步操作
      1. 基于http请求,将目标资源请求回本地,由 JS 引擎处理完成,而且 GUI 再继续向下渲染
      2. script 标签默认会阻塞 GUI 的渲染
      3. window.onload 触发条件,所有资源都加载完成(包含 DOM TREE/CSS/图片等资源)
      4. DOMContentLoaded, DOM TREE加载完即可
    2. async 属性
      1. 遇到 <script async></script> 首先会开启 HTTP 请求加载 JS 资源
      2. GUI 渲染线程会继续向下渲染,将默认改为了异步
      3. 一旦资源请求回来就会中断 GUI 的渲染,先把请求回来的 JS 进行渲染解析(不记录顺序)
    3. defer 属性
      1. 遇到 <script defer></script> 和 async 一样,开启 HTTP 网络请求加载资源
      2. 此时 GUI 还会继续渲染,执行异步操作
      3. defer 和 link 类似,是在 GUI 同步代码渲染之后才会执行取回的 JS 资源
    4. 多媒体资源(img video)
      1. 异步操作,遇到请求之后开启 HTTP 线程去加载资源
      2. 异步操作不会阻塞 GUI 的渲染 (老版本浏览器会阻塞GUI渲染)
      3. 当 GUI 渲染完成之后才会处理请求回来的资源(link defer)
    5. 预测解析
      1. webkit 浏览器预测解析,chrome 的预加载扫描器 html-preload-scanner 通过扫描节点中的 src link 等属性,找到外部链接资源后进进预加载
      2. 上述操作可以避免资源加载的等待时间,同样实现了提前加载以及加载和执行分离

1.2 页面渲染步骤

  1. DOM TREE(DOM树):自下而下渲染页面,整理好整个页面的 DOM 结构关系
  2. CSS TREE(样式树):当把所有的样式资源请求回来之后,按照引入 CSS 的顺序,依次渲染成样式代码,生成样式树
  3. RENDER TREE(渲染树):把生成的DOM树和CSS树结合在一起,生成渲染树(默认隐藏的元素不在渲染树中)
  4. Layout布局、回流、重排:依据生成的渲染树,计算元素们在设备视口(viewport)内确切位置和大小,这个过程是回流
  5. 分层处理:按照层级定位分层处理,每个层级都会有自己的绘制步骤
  6. Painting 绘制(重绘):将每层计算好的绘制步骤,开始绘制页面,依据渲染树及回流得到的几何信息,获取节点绝对像素,最后执行绘制

1.3 DOM 树生成

  • 从服务器获取到字节流(进制编码)
  • 将进制编码编译为具体的字符
  • 根据TOKEN解析生成不同的Tag(词法解析,就比如什么标签在哪里闭合之类的)
  • 生成具体的节点
  • 按照相互的对照关系生成DOM TREE

1.4 CRP 关键节点及优化

  1. 不使用 @import 导入样式
  2. link放在文档前面(尽可能提前加载,这样等DOM树加载完,我们的资源可能也加载回来了) 当代浏览器的功能愈发完善,像chrome有预解析会扫描节点中的link和src属性,找到外部资源后进行预加载 (提前加载样式资源,利用渲染树快速生成)
  3. 如果样式代码比较少的情况下,尽可能使用内嵌式,可以减少HTTP请求,移动端开发内嵌优先
  4. 如果使用link, 尽可能将样式写进一个资源文件,这样可以减少http请求
  5. 减少DOM(利用伪元素),减少DOM的层级嵌套,以及标签语义化(当代前端开发,开始只是把首屏的结构/内容写出来;页面滚动时,再基于JS创建其他屏幕的结构和内容 => 骨架屏/SSR => 客户端骨架屏,开始首屏结构都没有,只有一个loading/占位图而已)
  6. 减少 DOM或者减少 DOM 层级嵌套,标签语义化(开发时只把首屏结构写出来,只渲染首屏,等待首页渲染完成之后页面滚动时再基于 JS 创建其它屏的结构和内容,骨加屏/SSR)
  7. 把script放到页面底部(先渲染DOM TREE,再执行JS,也可以获取到DOM元素了)
  8. 图片合并(精灵图)/ base64(base64 会新增大概33%的图片文件体积)/svg(浏览器处理svg效率较低,不如png)
  9. 图片合并、Base64、图片懒加载

1.5 回流和重绘

1.5.1 名词

  1. 回流:元素的大小或者位置发生了变化(页面布局和几何信息发生变化)触发重新布局,渲染树重新计算布局和渲染
    1. DOM 元素增删改查致结构发生改变
    2. DOM 样式(大小或者位置)发生改变
    3. DOM 内容发生改变
    4. 浏览器窗口大小发生改变(视口)
    5. 第一次加载必然会有一次回流
  2. 重绘:元素样式发生改变(但宽高、大小、位置信息不变)
  3. 回流一定会触发重绘,而重绘不一定会回流

1.5.2 优化方式

  1. 回流优化
    1. 使用文档碎片操作DOM
    2. 使用字符串拼接操作DOM
    3. 放弃传统DOM操作,基于 VUE/React
    4. 分离读写操作(设置和获取分开)
    5. 集中样式改变(设置样式操作集中写在一起)
    6. 缓存布局信息(将修改之前的样式保存在变量中)
    7. 元素批量修改
    8. 尽可能分层(但第一次渲染会慢),当前元素如果具备 position:absolute/fixed再或者具备 opacity/filters等属性,此时在修改样式或执行动画时会优化回流速度(只是优化回流,不是不回流)因为这些元素在重绘的时候只影响当前层
    9. 基于 transform 修改元素样式可以直接跳过渲染树,直接执行重绘,不回流
  2. 重绘
    1. 浏览器渲染队列机制, 上一行代码如果是修改元素的样式,此时并没有直接通知浏览器去渲染,
    2. 把它放置在浏览器渲染队列当中,继续向下执行代码,把执行遇到的修改样式操作全部放置到浏览器渲染队列中
    3. 如果不再有修改样式的操作,或者遇到了获取样式的操作则中断队列存放操作把队列中的渲染操作执行一次(引发一次回流)继续向下执行代码

1.5.3 渲染进程

const oBox = document.getElementById('root')
oBox.onclick = function () {
  // 立即回到左侧
  oBox.style.left = 0 
  oBox.style.top = 0
  oBox.style.transitionDuration = '0s'

  // oBox.offsetLeft

  // 移动到别外
  oBox.style.transitionDuration = '1s'
  oBox.style.left = '400px'
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容