深入前端渲染-performance

285 阅读10分钟

浏览器

  • 浏览器是多进程的,js是单线程的。进程:程序运行,资源分配。线程:进程中独立执行的流
  • 浏览器有哪些进程

Browser进程: 浏览器的主进程(负责协调、主控)

GPU进程: 最多一个,用于3D绘制等

浏览器渲染进程:默认每个Tab页面一个进程,互不影响

第三方插件进程:每种类型的插件对应一个进程,仅当使用该插件时才创建

注:在浏览器中打开一个网页相当于新起了一个进程(进程内有自己的多线程)

  • 浏览器内核(渲染进程)是多线程的

**GUI渲染线程与JS引擎线程互斥:**由于JavaScript是可操纵DOM的,如果在修改这些元素属性同时渲染界面(即JS线程和UI线程同时运行),那么渲染线程前后获得的元素数据就可能不一致了。

url到render

第一阶段:Browser进程

浏览器输入url -> 浏览器主进程接管,开一个下载线程 -> http请求(DNS解析、TCP协议的三次握手和四次挥手、HTTPS和HTTP的区别(HTTP2)等等操作)-> 等待响应,获取内容 -> 通过RendererHost接口转交给Renderer进程

第二阶段:Renderer进程 浏览器内核

渲染进程处理 Web 页面的所有内容

文档—>DOMTree —> CSSDOM —> Layout —> LayerTree —> paint -> composite —> raster(位图) —> GPU绘制

DomTree构建 DOM 树: html 转换为 DOM 树

Style样式计算:

将css文本转换为 styleSheet。document.styleSheets
标准化属性值(em, rem, 字体的加粗(blod),颜色等)。
计算 DOM 树中的每个节点的样式 ComputedStyle

Layout布局: 计算 DOM 树中的 可见元素 的几何位置,生成布局树。

LayerTree分层:为特定的节点生成专用的图层,生成图层树(图层叠加后合成最终页面)

并不是布局树中的每个节点都会生成图层。
如果这个节点没有对应的层,那么它属于父节点的图层。
拥有层叠上下文属性的元素会生成新的层

Composite合成层:特定css属性节点:(position:fixed||stiky & 位置不为空...)

Paint图层绘制: 把图层绘制拆分为绘制指令,按照顺序组成待绘制列表,主线程把待绘制列表交给合成线程,合成线程把图层分为图块(tiles)。

Raster栅格化: 把图块转换成位图,生成的位图保存在 GPU 内存中。

Display合成和显示:提交给浏览器进程DrawQuad消息进行绘制,最终显示在屏幕上。

onReadyStateChange、DOMContentLoaded

Chrome Performance 工具

googlechrome.github.io/devtools-sa… demo

performance

performance面板有如下四个窗格:

  1、controls。开始记录,停止记录和配置记录期间捕获的信息

  2、overview。页面性能的高级汇总(W、A、S 和 D 键调整您的选择。 W 和 S 分别代表放大和缩小。 A 和 D 分别代表左移和右移)

  3、火焰图。 CPU 堆叠追踪的可视化

  4、统计汇总。以图表的形式汇总数据

Redering

小功能:查看合成层、显示实时FPS面板

Layer

合成层细节和原因

window.performance

前端性能监控和报警

memory字段代表JavaScript对内存的占用。chrome拓展对象

navigation字段统计的是一些网页导航相关的数据:

  1. redirectCount:重定向的数量(只读),但是这个接口有同源策略限制,即仅能检测同源的重定向;
  2. type 返回值应该是0,1,2 中的一个。分别对应三个枚举值:
  • 0 : TYPE_NAVIGATE (用户通过常规导航方式访问页面,比如点一个链接,或者一般的get方式)
  • 1 : TYPE_RELOAD (用户通过刷新,包括JS调用刷新接口等方式访问页面)
  • 2 : TYPE_BACK_FORWARD (用户通过后退按钮访问本页面)

最重要的是timing字段的统计数据,它包含了网络、解析等一系列的时间数据。

  • startTime:有些浏览器实现为navigationStart,代表浏览器开始unload前一个页面文档的开始时间节点。比如我们当前正在浏览baidu.com,在地址栏输入google.com并回车,浏览器的执行动作依次为:unload当前文档(即baidu.com)->请求下一文档(即google.com)

  • 如果当前文档为空,则navigationStart的值等于fetchStart。

  • redirectStart和redirectEnd:如果页面是由redirect而来,则redirectStart和redirectEnd分别代表redirect开始和结束的时间节点;

  • unloadEventStart和unloadEventEnd:如果前一个文档和请求的文档是同一个域的,则unloadEventStart和unloadEventEnd分别代表浏览器unload前一个文档的开始和结束时间节点。否则两者都等于0;

  • fetchStart是指在浏览器发起任何请求之前的时间值。在fetchStart和domainLookupStart之间,浏览器会检查当前文档的缓存;

  • domainLookupStart和domainLookupEnd分别代表DNS查询的开始和结束时间节点。如果浏览器没有进行DNS查询(比如使用了cache),则两者的值都等于fetchStart;

  • connectStart和connectEnd分别代表TCP建立连接和连接成功的时间节点。如果浏览器没有进行TCP连接(比如使用持久化连接webscoket),则两者都等于domainLookupEnd;

  • secureConnectionStart:可选。如果页面使用HTTPS,它的值是安全连接握手之前的时刻。如果该属性不可用,则返回undefined。如果该属性可用,但没有使用HTTPS,则返回0;

  • requestStart代表浏览器发起请求的时间节点,请求的方式可以是请求服务器、缓存、本地资源等;

  • responseStart和responseEnd分别代表浏览器收到从服务器端(或缓存、本地资源)响应回的第一个字节和最后一个字节数据的时刻;

  • domLoading代表浏览器开始解析html文档的时间节点。我们知道IE浏览器下的document有readyState属性,domLoading的值就等于readyState改变为loading的时间节点;

  • domInteractive代表浏览器解析html文档的状态为interactive时的时间节点。domInteractive并非DOMReady,它早于DOMReady触发,代表html文档解析完毕(即dom tree创建完成)但是内嵌资源(比如外链css、js等)还未加载的时间点;

  • domContentLoadedEventStart:代表DOMContentLoaded事件触发的时间节点:

  • 页面文档完全加载并解析完毕之后,会触发DOMContentLoaded事件,HTML文档不会等待样式文件,图片文件,子框架页面的加载. document.ready

  • domContentLoadedEventEnd:代表DOMContentLoaded事件完成的时间节点,此刻用户可以对页面进行操作,也就是jQuery中的domready时间;

  • domComplete:html文档解析完成、网页内资源准备就绪;

  • loadEventStart和loadEventEnd分别代表onload事件触发和结束的时间节点

1. DNS 查询耗时

domainLookupEnd - domainLookupStart,如果使用了 DNS 缓存或采用了持久连接,值为 0

2. TCP链接耗时

connectEnd - connectStart,如果采用了持久连接,值为 0

3. request请求耗时

responseStart - fetchStart,这个指标可以反映出网络和后端处理的整体耗时

4、解析dom树耗时

= domComplete - domInteractive

5. 白屏时间

白屏时间指页面展示出第一个元素的时间,主要通过看到是 DOM 解析完成的时间,domInteractive - fetchStart

6. 首屏时间(onload时间)

首屏时间指第一屏页面完全展示完毕的时间,loadEventStart - fetchStart

知道这些有什么用呢?难道就是为了装一下X吗?

performanc优化

从渲染流程总结性能优化,先看一下优化标准

RAIL(Response、Animation、Idle、load)性能评估模型

以用户为中心;最终目标不是让您的网站在任何特定设备上都能运行很快,而是使用户满意。

  • 立即响应用户;在 100 毫秒以内确认用户输入。
  • 设置动画或滚动时,在 10 毫秒以内生成帧。 1000/10=100fps
  • 最大程度增加主线程的空闲时间。 50 毫秒
  • 持续吸引用户;在 1000 毫秒以内呈现交互内容。 渐进式渲染、主要内容渲染

渲染流程总结性能优化

一、DNS 解析

每次dns解析大概需要20-120毫秒

  • 允许使用浏览器DNS缓存机制 (IE缓存30分钟、Firefox ]&Chrome缓存 1 分钟 )
  • 减少DNS查询 (组件分散在 2~4 个域名下)
  • dns-prefetch www.taobao.com/

DNS prefetching 允许浏览器在用户浏览页面时在后台运行 DNS 的解析

二:http请求

  • preconnect 允许浏览器在一个 HTTP 请求正式发给服务器前预先执行一些操作(DNS 解析,TLS 协商,TCP 握手)
    • 减少tcp连接时间:http Keep-Alive
  • http头文件最小化 (Cookie压缩、使用不带 Cookie 的域名)
  • 减少http请求次数和大小 (避免 src、href空值、js、css、icon、third party plugins、Use less code)
  • 避免301/302重定向(重定向将产生额外的往返时间)
  • 最大化下载线程:使用不同的域名可以最大化下载线程,但注意保持在 24 个域名内,以避免 DNS 查询损耗(iE 813 chrome&firebox 6)
  • HTTP/2:1、头文件压缩 2、多路复用的单一长连接 3、服务端推动Sever Push
  • 打包配置优化

三:render

  • preload 允许浏览器预加载在 CSS 和JavaScript 中定义的重要资源
  • **图片优化:**图片压缩、图片cdn、预加载、懒加载 getBoundingClientRect()

  • 避免Dom阻塞

避免css阻塞render-tree渲染 (选择器、less css、minify)

避免加载js阻塞render-tree生成 (async or defer)

避免js引擎线程阻塞GUI渲染线程

  • 延迟加载:页面初始加载时哪些内容是绝对必需的?(渐进增强、懒加载)
  • 预加载:利用浏览器空闲的时间
  • 减少dom数量 (document.getElementsByTagName('*').length)
  • 减少重绘和回流
    • 一定会引起layout的属性:“

offsetTop、offsetLeft、offsetWidth、offsetHeight

scrollTop、scrollLeft、scrollWidth、scrollHeight

clientTop、clientLeft、clientWidth、clientHeight

getComputedStyle()

getBoundingClientRect()

  • 需要大量操作的dom直接删除,新增

  • requestAnimationFrame

  • 避免频繁操作样式,最好一次性重写style属性

  • Composite 开启硬件加速

  1. 最常用的方式:translate3d、translateZ
  2. will-chang属性(这个比较偏僻),一般配合opacity与transform使用(其它属性并不会变成复合层), 作用是提前告诉浏览器要变化,这样浏览器会开始做一些优化工作(用后释放)
  3. opacity属性/过渡动画(需要动画执行的过程中才会创建合成层,动画没有开始或结束后元素还会回到之前的状态)
  4. <canvas><webgl>等元素

三:缓存

CDN缓存

  • 针对静态资源,所有正常状态码(大于等于 200 小于 400)均缓存 8 天。特别地,301 响应缓存 2 小时,302 响应缓存 20 分钟;
  • 针对动态资源,程序会自动识别,则不进行缓存;
  • 对于其他大于等于 400 的不正常响应,则不进行缓存;
  • 缓存节点通知浏览器缓存的具体时间由 HTTP 响应头里面的 Cache-Control 和 Expires 响应头控制。

浏览器缓存

  • Expires 有效期
  • Cache-Control max-age
  • Last-Modified 日期
  • ETag 文件版本标记

有趣的现象

  • 如果从A⻚面打开B⻚面,且A和B都属于同一站点(相同的协议和根域名)的话,那么B⻚面复用A⻚面的渲染进程;如果是其他情况,浏览器进程则会为B创建一个新的渲染进程。eg:zhidao.baidu.com

  • Cookie设置在第一域名时,在其子域名中无法删除

参考文章

web.dev/rail/

www.keycdn.com/blog/websit…

推荐文章

Life of a pixel

Resource Hints - What is Preload, Prefetch, and Preconnect?

developers.google.com/web/tools/c…

webkit技术内幕

思考问题:前端数据监控、预警系统搭建