记一次惊心动魄的前端性能优化之旅

二叶草 2020年2月3日10:31:07优化评论阅读模式

我司全球购业务改版,将原生的全球购页面采用 Hybird 模式开发,这是我司 H5 页面第一次出现在以及入口位置,作为开发者显得很是兴奋。

第一阶段 - 问题初显

问题

根据设计稿,如期完成工作,测试也已准备好,部分 Android 低端机中显示出卡顿现象,出于对自身技能的肯定,误以为是硬件性能问题,并未引起过多关注。

方案

未引起重视,并没有做出相应处理。

第二阶段 - 引起重视

问题

上到 pre 环境后,发现部分 iPhone 机型出现崩溃,初步排查在 iOS 8.4 系统上 DOM 节点高度达到 10000px 以上奔溃率 100%,其他 8-9 之间的系统版本当分页数据使得 DOM 达到 10000px 以上快速滚动会出现卡顿,9 以上 iOS 系统与 Android4.4 以上系统均表现良好。定位问题后,迅速进行更多特殊机型与相应系统的测试,期间借遍了公司几百位小伙伴的手机,在此向他们表示感谢。

你问我为什么,我只能说测试环境没有这么多数据,至于为什么没有?呵呵,你懂得!

方案

  1. iOS 将 UIWebview 切换为 WKWebview,WKWebview 为 iOS 在 8 以上系统中新加入的一个高性能 Webview,具体哪里好,可以点这里、这里、还有这里 (后台问小编链接吧),由于 iOS 已经发版(对的,在 H5 页面还在 pre 环境测试的时候,iOS 已经发版了)这个方案只能作为下一个版本了

  2. 临时降低数据显示总量,同时寻找性能瓶颈(这里要和运营的同学说声 sorry)

实施

针对 iOS 8 以下以及 8.4 系统 Android 4.4 以下系统做自动降级处理。

一些经验

  1. 测试不能仅仅做功能测试,还要做性能测试

  2. 开发人员常使用 chrome、Firefox 等浏览器的开发工具进行开发,这里要注意的是:浏览器开发工具只能模拟手机 UI 与交互,其性能要远远强于手机环境。

  3. 开发过程中常用微信、QQ、手机浏览器进行测试,这是不可取的,因为最终环境不一,容易给自己造成错觉,觉得在微信 QQ 的 Webview 中没问题,就 OK 了

  4. deadline 真的要好好定。很多人认为 H5 很灵活,并不依赖于 iOS 发版,可以将测试定在 iOS 发版的那几天进行。其实这真的是巨大的错误,后面我会说明。

第三阶段 - 全面升级

经过降级后,仍然存在很多问题,同时我们也在抓紧研究后续升级方案。经过协调,将系统切回了老版本暂时使用原生替代 H5(感觉很受打击~)。

问题

  1. 数据量不足,对运营影响很大

  2. 对降级机型的体验很差,数据统计显示,受影响的机型还是有一定份额

  3. 由于此次 H5 是存在于以及目录,所以设计上是常驻内存以保证体验,UIWebview 的内存一直得不到释放,同事系统中其他页面也使用到了 UIWebview,长时间使用仍然会出现崩溃。

  4. 距离 iOS 和 Android 下一次发版还有一段时间,不可能一直降级

无论如何解决性能问题,这是唯一目标!经过一个星期枯燥而漫长的努力与实验,从以下几个方面彻底解决了性能瓶颈;

方案

1.去除 iScroll

iScroll 是我们内部框架中引入的一个第三方组件,官方的介绍是「Smooth scrolling for the web」,奈何在大数据量面前性能确实令人堪忧。如果数据量少,还是推荐使用的。

2.高性能 DOM 渲染

 

在对比了竞品,和天猫、JD 等知名厂商 H5 实现后,确实郁闷了一段时间,同样的数据量为什么别人可以做到?最后得到两个结论:

  • 别人 DOM 节点没我们复杂,由于我们采用了内部研发的 m-fast 框架,框架顶层就确定了 DOM 结构的复杂性,例如:框架预设了整个布局为上、下、左、右、中的布局,即使我的页面只是一个流式布局。

  • 别人 H5 页面没有图片轮播!对,你没看错,一个图片轮播居然对性能影响如此之大

居于上面这两点,我开始了 DOM 性能研究

记一次惊心动魄的前端性能优化之旅

m-fast 框架采用模板预编译技术,将页面模板编译为 js 文件,在通过异步加载的方式载入,所以,网页的渲染大致符合上面这五个步骤

  • 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 元素的绘制是在多个层上进行的。在每个层上完成绘制过程之后,浏览器会将所有层按照合理的顺序合并成一个图层,然后显示在屏幕上。对于有位置重叠的元素的页面,这个过程尤其重要,因为一旦图层的合并顺序出错,将会导致元素显示异常。

     

    记一次惊心动魄的前端性能优化之旅

如果你修改一个 DOM 元素的“paint only”属性,比如背景图片、文字颜色或阴影等,这些属性不会影响页面的布局,因此浏览器会在完成样式计算之后,跳过布局过程,只做绘制和渲染层合并过程。

记一次惊心动魄的前端性能优化之旅

如果你修改一个非样式且非绘制的 CSS 属性,那么浏览器会在完成样式计算之后,跳过布局和绘制的过程,直接做渲染层合并。这种方式在性能上是最理想的,对于动画和滚动这种负荷很重的渲染,我们要争取使用这种渲染流程。

最终得出以下几点改进:

1. 简化浏览器重绘的复杂度

绘制,是填充像素的过程,这些像素将最终显示在用户的屏幕上。通常,这个过程是整个渲染流水线中耗时最长的一环,因此也是最需要避免发生的一环。

  • CSS 属性中,除了 transform 和 opacity 之外,修改任何属性都会触发绘制

  • 如果布局被触发,那么接下来绘制一定会被触发。因为改变一个元素的几何属性就意味着该元素的所有像素都需要重新渲染!

  • 如果改变元素的非几何属性,也可能触发绘制,比如背景、文字颜色或者阴影效果,尽管这些属性的改变不会触发布局。

2. 减小浏览器重绘区域

绘制并非总是在内存中的单层画面里完成的。实际上,浏览器在必要时将会把一帧画面绘制成多层画面,然后将这若干层画面合并成一张图片显示到屏幕上。

记一次惊心动魄的前端性能优化之旅

这种绘制方式的好处是,使用tranforms来实现移动效果的元素将会被正常绘制,同时不会触发对其他元素的绘制。

在页面中创建一个新的渲染层的最好方式就是使用 CSS 属性 will-change,Chrome/Opera/Firefox 都支持该属性。同时再与 transform 属性一起使用,就会创建一个新的组合层:

.moving-element {
 will-change: transform;
}

对于那些目前还不支持 will-change 属性、但支持创建渲染层的浏览器,比如 Safari 和 Mobile Safari,你可以使用一个 3D transform 属性来强制浏览器创建一个新的渲染层:

.moving-element {
 transform: translateZ(0);
}

但需要注意的是:不要创建太多的渲染层。因为每创建一个新的渲染层,就意味着新的内存分配和更复杂的层的管理。

3. 避免大规模、复杂的布局

上面提到的,由于框架的限制,页面布局相对需求来说复杂很多。开发中应该尽量避免复杂的 DOM 结构,复杂的 DOM 结构更容易引起大面积的重绘。

4. 优先使用渲染层合并属性

渲染层的合并,就是把页面中完成了绘制过程的部分合并成一层,然后显示在屏幕上。

使用transform/opacity来实现动画效果,目前只有transforms和opacity这两个属性不会触发浏览器的布局和绘制,对网页元素这两个属性的修改会直接触发渲染层合并。

5. 优化 JavaScript 的执行效率
 
  • 对于动画效果的实现,避免使用 setTimeout 或 setInterval,请使用 requestAnimationFrame。

  • 把耗时长的 JavaScript 代码放到Web Workers中去做。

 

这里可以使用 Chrome DevTools 的 Timeline 和 JavaScript Profiler 来分析 JavaScript 的性能。

写在最后

性能优化是一门做减法的艺术。我们首要要尽力简化页面渲染过程,然后要使渲染过程的每一步都尽量高效。

 

本文来源于:记一次惊心动魄的前端性能优化之旅-变化吧门户
特别声明:以上文章内容仅代表作者本人观点,不代表变化吧门户观点或立场。如有关于作品内容、版权或其它问题请于作品发表后的30日内与变化吧联系。

 

在寻找靠谱的建站服务?

提供建站全方位托管服务,告诉我你的需求,剩下的交给我帮你处理,建站过程中碰到的任何小问题免费处理,网站所有数据由你自己掌握,还提供网站SEO指导,犹豫什么呢?联系我吧。

 

  • 赞助本站
  • 微信扫一扫
  • weinxin
  • 加入Q群
  • QQ扫一扫
  • weinxin
二叶草
nginx解析漏洞 优化

nginx解析漏洞

phpstudy(小皮模板存在nginx解析漏洞) 影响版本 phptsuy8.1.07的Nginx1.5.11版本影响版本 phptsuy8.1.07的Nginx1.5.11版本 phpstudy介...
网站SEO优化基础流程(新手必看) 优化

网站SEO优化基础流程(新手必看)

宝塔面板搭建一个获取网站的Favicon图标的APIgetFavicon是一个可以获取网站的Favicon图标并显示在你的网页上的项目。安装方法很简单,属于开箱即食。这篇文章还是基于宝塔面板来搭建。 ...

发表评论