页面性能优化的利器 — Timeline

作者介绍:陈泽钦,腾讯移动客户端工程师,目前就职于腾讯MIG移动互联网事业群,负责腾讯浏览服务TBS的X5内核业务。

1. 网页渲染的基础

在前面整理的Chrome官方的渲染性能优化文章中,讲述到了网页生成过程中,主要包含如下几个步骤:

* JavaScript。一般来说,我们会使用JavaScript来实现一些视觉变化的效果。比如用jQuery的animate函数做一个动画、对一个数据集进行排序、或者往页面里添加一些DOM元素等。当然,除了JavaScript,还有其他一些常用方法也可以实现视觉变化效果,比如:CSS Animations, Transitions和Web Animation API。

* 计算样式。这个过程是根据CSS选择器,比如.headline.nav > .nav_item,对每个DOM元素匹配对应的CSS样式。这一步结束之后,就确定了每个DOM元素上该应用什么CSS样式规则。

* 布局。上一步确定了每个DOM元素的样式规则,这一步就是具体计算每个DOM元素最终在屏幕上显示的大小和位置。web页面中元素的布局是相对的,因此一个元素的布局发生变化,会联动地引发其他元素的布局发生变化。比如,元素的宽度的变化会影响其子元素的宽度,其子元素宽度的变化也会继续对其孙子元素产生影响。因此对于浏览器来说,布局过程是经常发生的。

* 绘制。绘制,本质上就是填充像素的过程。包括绘制文字、颜色、图像、边框和阴影等,也就是一个DOM元素所有的可视效果。一般来说,这个绘制过程是在多个层上完成的。

* 渲染层合并。由上一步可知,对页面中DOM元素的绘制是在多个层上进行的。在每个层上完成绘制过程之后,浏览器会将所有层按照合理的顺序合并成一个图层,然后显示在屏幕上。对于有位置重叠的元素的页面,这个过程尤其重要,因为一旦图层的合并顺序出错,将会导致元素显示异常。

参考tikizheng在Timeline的入门篇中所整理的框图,更清晰地展示了页面生成的流程。

网页中的重绘过程是影响整体性能下降的关键点之一,因而网站开发者应该更多地去避免在站点中进行不必要以及不适时的重绘步骤,借助Inspector中的Timeline面板可以很好地剖析这一些存在的问题。

2. 实例讲解

在此,本文将通过一个简单的网页Demo来讲述Timeline的常用技巧

Demo页面,具体如下:


<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>X5 CORE</title>
    <style type="text/css">
        body { font-size: 16px }
        p { font-weight: bold }
        span { color: red }
        p span { display: none }
        img { width: 100%; max-width: 300px }
    </style>

    <script>
      function a_click() {
        var span = document.getElementsByTagName('span')[0];
        span.textContent = 'Web performance'; // change DOM text content, lead to relayout
        span.style.color = 'green';  // change CSSOM property
      }
    </script>
  </head>

  <body>
    <p>Hello <span>web performance</span> students!</p>
    <div><img src="X5.jpg" onclick="a_click()"></div>
    <script>
      var span = document.getElementsByTagName('span')[0];
      span.textContent = 'interactive'; // change DOM text content
      span.style.display = 'inline';  // change CSSOM property
      // create a new element, style it, and append it to the DOM
      var div = document.createElement('div');
      div.textContent = '*** Add new element to DOM ***';
      div.style.color = 'blue';
      document.body.appendChild(div);
    </script>
  </body>
</html>

这是一个很简单的网页,展示了一行文字和图片,而在body中有一段script对个别元素进行样式和内容的调整;此外还有一个点击事件,即点击图片后,会再次执行一段修改元素内容和样式的脚本。

2.1 操作流程:

  • Ctrl+E 开始录制
  • 刷新页面
  • 点击图片,执行onclick事件
  • Ctrl+E 结束录制

操作完毕后,Inspector在Timeline中记录了这一过程中,与页面相关的各项信息。

可以看到下图中上方的两个红色框位置,该区域是Timeline面板的整体预览区,分了三部分(FPS、CPU、NET)来展示,具体可查看Timeline使用详情。首个红色框位置,记录了首次加载页面时,所经历的Loading -> Scripting -> Rendering -> Painting流程。而右边的红色框区域中,可见CPU中首先显示了黄色(代表Scripting)的峰形区域,随后显示了紫色(代表Rendering)的峰形区域,表示了页面在响应点击事件后所进行的流程。

2.2 事件详解:

通过滚轮在Flame框图中,可以对页面中的事件进行缩放,可已清晰地观察到在首次加载过程中,所经历的Loading -> Script -> Layout -> Paint -> Composite Layers等流程。

并且,在点击了各个事件之后,下方的Summary中会罗列出更加具体的信息。比如,点击Evaluate Script事件后,可以查看总共的耗时,并且可以链接到具体的JS源代码:

而在网页加载完毕后,对图片进行了点击操作,触发了<img />标签的onclick事件,开发者能够在Flame框图中查看到点击事件中各个流程,其展现了所有的JS调用栈

系统Event(click) ==> <img />绑定的onclick事件(html中第24行) ==> function a_click() (html中第14行)

2.3 综合分析

由此可见,当在页面已经得到生成了之后,利用JS去更改个别元素的内容(DOM结构变化),或者是调整元素属性(CSSOM属性变化),都会引起页面重新进行Rendering -> Painting流程。如果这些是不必要的操作,则必定会导致网页性能降低。

因此,对于开发者来说,应该要知道如何去定位网页中发生重绘的区域

3. 定位网页中发生重绘的区域

开启方式:在控制栏的右上角属性按钮中,选择More tools — Rendering settings,然后在弹出的面板中选择 Paint Flashing

如下图中的操作,在勾选了Paint Flashing后,还是在Demo页面中,点击图片触发JS事件,进而会span标签的内容以及颜色,而在页面预览区域中,可以观察到该行文本在刷新内容过程中,有绿色的方框进行高亮包围,说明了这一部分区域发生了重新绘制

另外一个重要的现象是,虽然点击后的JS事件仅修改了<span>的内容,但是重绘却发生在整一个<p>标签中,说明了个别元素的重新绘制,一般会影响到父元素或者是周围的元素,造成区域性重绘,因此在页面中避免不必要的重绘显得至关重要。

小技巧: 当发现页面中,如果存在一些不必要的重绘现象,而又不能够定位到具体的原因,可以对该区域中的各个元素,依次进行隐藏(在Element面板中设置visibility:hidden),观察效果来定位。

4. 显示composited layer的边界

More tools — Rendering settings中,还可以开启 Layer Borders,观察页面中的各个区域绘制情况。通过这一项功能,开发者能够发现页面中发生动画或者是CSS transforms/transitions等发生了形状或位置变化的元素,进而优化其渲染时间

Demo页面比较简单所以效果不明显,利用官方图片来展示Layer Borders的效果:

5. 在Paint Profiler中查看绘制细节

当在Flame框图中点击了 一个Paint事件,则会在详情面板中出现一个Paint专有标签:Paint Profiler

通过Paint Profiler面板,开发者可以知道该次Paint事件的绘制时间、绘制位置和大小等信息,并且能够具体到某一个元素的绘制耗时:当拖动标尺,直至内容框中仅有目标元素Image的绘制时,即可观察到其耗时(0.14ms/0.2ms),以及图片区域的大小、位置等等信息。

原创声明,本文系作者授权云+社区-专栏发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

陈泽钦的专栏

1 篇文章1 人订阅

我来说两句

2 条评论
登录 后参与评论

相关文章

来自专栏Young Dreamer

基于Webkit的浏览器关键渲染路径介绍

关键渲染路径概念 浏览器是如何将HTML、JS、CSS、image等资源渲染成可视化的页面的呢?本文简单介绍一下渲染过程中涉及到的关键步骤。 该过程分为四步:模...

1919
来自专栏FreeBuf

安全科普:SQLi Labs 指南(Part 3)

Freebuf上有两篇SQLi Labs的教程安全科普:SQLi Labs 指南 Part 1和安全科普:SQLi Labs 指南 Part 2。这两篇教程只讲...

1919
来自专栏DeveWork

Normalize.css ——CSS Reset的友好替代品

最近才第一次接触这个Normalize.css,之前Jeff 都是采用CSS Reset的,但如今发现现在流行这个Normalize.css 了。自己也查阅了不...

1669
来自专栏微信小程序开发

小程序中图片高度等比缩放

前言:小程序中的image组件,有默认的宽度(320px)和高度(240px),如果想让图片按比例显示,那就需要自己设置宽度 & 高度。今天来说一下图片等比缩...

39510
来自专栏Hongten

java开发_模仿百度文库_FlexPaper

下载地址:http://code.google.com/p/flexpaper/downloads/list

651
来自专栏技术碎碎念

数据的分页处理

当页面中要显示的内容过多需要分多页显示、或是数据量过大内存吃不消时,需要分页处理。 原理:每次从数据库中取出一定量的数据,通过jsp页面显示 实现: ①写一个类...

2465
来自专栏前端架构与工程

从零开始搭建前端数据监控系统(一)-同类产品调研

1 Google Analytics GA向window暴露一个名为ga()的全局函数,ga()函数以参数格式、数目来分发不同的行为。这种模式的好处是API单一...

1945
来自专栏DeveWork

WordPress免插件仅代码实现面包屑导航

这个功能在网络上一搜是一大把代码,本来也不想在这里再累赘的,但为了丰富本站 DeveWord .com 的“无插件”系列,只得。。。面包屑导航不仅仅是给访客使用...

17710
来自专栏Nian糕的私人厨房

CSS banner图响应式居中显示

在 PC 网站首页,banner 图作为网页中最大的一张图片,在传达网页的的主要信息的同时,也吸引着浏览者的所有注意力,所以 banner 图的展示方式直接影响...

573
来自专栏小詹同学

Python爬虫实例之——小说下载

这是小詹关于爬虫的第②篇文章! 第一篇关于爬虫中介绍了一些基本的术语和简单的操作,这里不重复叙述了,直接放链接,不记得的自己在文章末尾点击前期链接补补~ 本篇开...

4445

扫码关注云+社区