高性能移动端开发

不知不觉,春节就过完了,还没来得及好好享受就没了。好想来一场说走就走的旅行??,不吹水了,直接进入正题。

最近在做一个需求,发现了薄弱的地方,趁这个好机会深入了解一下,拓宽一下视野~

众所周知,网页不仅应该被快速加载,同时还应该流畅运行,比如快速响应的交互,如丝般顺滑的动画……

在实际开发中如何做到上面所说的效果呢?

1. 确认渲染性能的分析标准

2. 准备尺子去衡量渲染性能标准

3. 对耗时多的地方进行优化

我们可以粗略的得到下面的优化目标

第一个是 首屏呈现时间,网上的资料已经非常非常多了,压缩代码,使用webp图片,使用sprite,按需加载,“直出”,CDN……

第二个是 16ms 优化,本篇重点讲16ms的优化。

一. 浏览器渲染原理介绍

大多数设备的刷新频率是60次/秒,(1000/60 = 16.6ms)也就说是浏览器对每一帧画面的渲染工作要在16ms内完成,超出这个时间,页面的渲染就会出现卡顿现象,影响用户体验。

这就是上图中的<16ms。浏览器在一帧里面,会做以下这些动作。 当然,有些步骤(比如 layout,paint)是可以省略的。

如果改变属性在上面图中越往左,那么影响就越大,效率就越低。

浏览器渲染的流程如下:

  1. 获取 DOM 并将其分割为多个层(RenderLayer)
  2. 将每个层栅格化,并独立的绘制进位图中
  3. 将这些位图作为纹理上传至 GPU
  4. 复合多个层来生成最终的屏幕图像(终极layer)。

从上面图中可以看出,如果只是改变composite(渲染层合并),那效率就会大大提高。

下面粗略地列出改变哪些样式会分别改变渲染过程的哪一模块。

从上图可以看到 transform,opacity 只会改变composite(渲染层合并),为什么呢?因为开启了GPU加速。

开启 GPU 加速

字面上的解释: 纹理能够以很低的代价映射到不同的位置,而且还能够以很低的代价通过把它们应用到一个非常简单的矩形网格中进行变形。

【字面上的理解非常地绕口,还是老道理,能用图讲清的道理不要用文字。】

小tips:先选中timeline的某一帧,然后选择下面的layer标签tab,可以左右拖动该模块出现3d

我们可以看到页面上由如下层组成:

虽然我们最终在浏览器上看到的只是一个复印版,即最终只有一个层。类似于PhotoShop软件中的“图层”概念,最后合并所有可视图层,输出一张图片到屏幕上

但是实际上一个页面会因为一些规则被分成相应的层,一旦被独立出来之后,便不会再影响其他dom的布局,因为它改变之后,只是“贴上”了页面。

目前下面这些因素都会引起Chrome创建层:

  • 3D 或透视变换(perspective transform) CSS 属性
  • 使用加速视频解码的 <video> 元素
  • 拥有 3D (WebGL) 上下文或加速的 2D 上下文的 <canvas> 元素
  • 混合插件(如 Flash)
  • 对自己的 opacity 做 CSS 动画或使用一个动画 webkit 变换的元素
  • 拥有加速 CSS 过滤器的元素
  • 元素有一个包含复合层的后代节点(换句话说,就是一个元素拥有一个子元素,该子元素在自己的层里)
  • 元素有一个 z-index 较低且包含一个复合层的兄弟元素(换句话说就是该元素在复合层上面渲染)
  • 在webkit内核的浏览器中,如果有上述情况,则会创建一个独立的layer。

需要注意的是,不要创建过多的渲染层,这意味着新的内存分配和更复杂的层管理。不要滥用GPU加速,注意看 composite layouts 是否超出了 16ms

说了这么多浏览器渲染的原理,如果没有尺子测量也毫无用处。那么,下面就选尺子去丈量:谷歌开发工具的Timeline。

二. 谷歌开发工具 Timeline 的常用功能

1. 点击左上角的录制之后,录制结束后会生成下面的样子,红色区域内就是帧了,移动上去可以看到每一帧的频率,如果>60fps,就是比较流畅,如果<60fps,就会感到卡顿

2. 在timeline下面,可以看到各个模块的耗时,可以定位到耗时较大的函数上面,对该函数进行优化。

3. 按照下面步骤选择,即可看到独立的层,高亮重绘的区域,方便找出不必要重绘的区域,进行优化

选择之后,当前页面会出现下面2中颜色边框

黄色边框: 有动画3d变换的元素,表示放到了一个新的复合层(composited layer)中渲染

蓝色的栅格:这些分块可以看作是比层更低一级的单位,Chrome以这些分块为单位,一次向GPU上传一个分块的内容。

工具也有了,浏览器渲染的原理也知道了,接下来是结合实际项目进行优化.

三. 在实际项目中进行 16.6ms 优化

结合上面的渲染流程图,我们可以针对性的分析并优化下面的一些步骤

  • 优化JavaScript的执行效率
  • 降低样式计算的范围和复杂度
  • 避免大规模、复杂的布局
  • 简化绘制的复杂度、减少绘制区域
  • 优先使用渲染层合并属性、控制层数量
  • 对用户输入事件的处理函数去抖动(移动设备)

1. 读写分离,批量操作 

JavaScript脚本运行的时候,它能获取到的元素样式属性值都是上一帧画面的,都是旧的值。

因此,如果你在当前帧获取属性之前又对元素节点有改动,那就会导致浏览器必须先应用属性修改,结果执行布局过程,最后再执行JavaScript逻辑。

// 先写后读,触发强制布局
function logBoxHeight() {
    // 更新box样式
    box.classList.add(‘super-big‘);

    // 为了返回box的offersetHeight值
    // 浏览器必须先应用属性修改,接着执行布局过程
    console.log(box.offsetHeight);
}

优化之后:

// 先读后写,避免强制布局
function logBoxHeight() {
    // 获取box.offsetHeight
    console.log(box.offsetHeight);

    // 更新box样式
    box.classList.add(‘super-big‘);
}

2. 闭包缓存计算结果   (需要频繁的调用,计算的函数)

 1 getMaxWidth: (function () {
 2             var cache = {};
 3             function getwidth() {
 4                 if (maxWidth in cache) {
 5                     return cache[maxWidth];
 6                 }
 7                 var target = this.node,
 8                     width = this.width,
 9                     screen = document.body.clientWidth,
10                     num = target.length,
11                     maxWidth = num * width + 10 * num + 20 - screen;
12                 cache[maxWidth] = maxWidth;
13                 return maxWidth;
14             }
15             return getwidth;
16 })(),

改成这种方式后,直接蹭蹭蹭~ 减少了10多ms

3. 对用户输入事件的处理函数去抖动

如果被触摸的元素绑定了输入事件处理函数,比如touchstart/touchmove/touchend,那么渲染层合并线程必须等待这些被绑定的处理函数执行完毕才能执行,也就是用户的滚动页面操作被阻塞了,表现出的行为就是滚动出现延迟或者卡顿。

简而言之就是你必须确保用户输入事件绑定的任何处理函数都能够快速的执行完毕,以便腾出时间来让渲染层合并线程完成他的工作。

输入事件处理函数,比如scroll/touch事件的处理,都会在requestAnimationFrame之前被调用执行。因此,如果你在上述输入事件的处理函数中做了修改样式属性的操作,那么这些操作就会被浏览器暂存起来。

然后在调用requestAnimationFrame的时候,如果你在一开始就做了读取样式属性的操作,那么将会触发浏览器的强制同步布局操作(即在javascript阶段中执行布局),这样会导致多次布局,效率低下。

优化如下:

window.requestAnimationFrame(function () {
    context.animateTo(nowPos);  //需要更新位置的交给RAF
});

4. 减少不必要的重绘

续上面,开启paint flashing 之后,可以看到浏览器重新绘制了哪些区域。发现有一些不必要重绘的区域也重绘了~给这些开启GPU优化(上文中提到)

直接看 timeline 效果,全绿了~悬着的心终于放下了

参考文章: http://www.jianshu.com/p/a32b890c29b1

时间: 2024-12-24 18:06:51

高性能移动端开发的相关文章

关于近期对于移动端开发的一些看法

首先移动端开发最基本的就是尺寸问题: <meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"/> 这行代码是肯定知道要加的,但是我们还会面临在不同尺寸的屏幕上对应尺寸的大小变化.对于这个问题我之前看过很多网站对于这个的处理,我主要是采用小米官网对于这个的修改,单位

web移动端开发技巧与注意事项汇总

一.meta的使用 1.<meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"/> 强制让文档的宽度与设备的宽度保持1:1,并且文档最大的宽度比例是1.0,且不允许用户点击屏幕放大浏览 2.winphone系统a.input标签被点击时产生的半透明灰色背景怎么去掉

29.html5 移动端开发总结

手机与浏览器 浏览器: 移动端开发主要针对手机,ipad等移动设备,随着地铁里的低头族越来越多,移动端开发在前端的开发任务中站的比重也越来越大.各种品牌及尺寸的手机也不尽相同.尺寸不同就算了分辨率,视网膜屏 自动的各种内核的浏览器,想想头都大了. 先说下浏览器.在中国有多少种浏览器? ie.百度.360.搜狗.火狐.欧朋.Chrome.谷歌.行者无疆.财猫省钱.遨游.Wise光速.UC.智慧.QQ.海豚...(大概有70-80多种) 五花八门,还好不用担心这都是表象.虽然浏览器各不相同但从浏览器

现代Java服务端开发核心技术栈

现代Java服务端开发核心技术栈 现代Java服务端开发核心技术 Java语言基础篇 互联网生态下的Java Java开发工具箱 Java基础项目搭建 Java数据存储 Java数据运算 Java程序流程控制 Java数组 Java面向对象程序设计 Java异常处理 Java枚举 Java注解 Java 泛型 Java集合 Java IO Java NIO Java操作数据库 Java日志 Java操作XML Java正则表达式 Java8新特性实战 Java9新特性实战 Java10新特性实战

菜鸟窝React Native 系列教程-1.移动端开发趋势与未来

菜鸟窝React Native 系列教程-1.移动端开发趋势与未来 课程持续更新中..... 我是RichardCao,现任新美大酒店旅游事业群的Android Developer.如果你也有兴趣录制RN视频,请加入下面QQ群找我. 下载地址:https://pan.baidu.com/s/1c1XmE56 密码:shhw 首发地址:菜鸟窝-ReactNative学习板块 交流QQ群:576089067 课程目录:菜鸟窝React Native 系列教程

WIFI物联网平台微信端开发分享

本文由企鹅圈原创成员Hunter_Zhu贡献. 本篇文章是基于近期一个项目微信端开发过程的一个总结.文中主要介绍了云智易平台下微信端开发的流程.该平台提供的主要功能以及此次H5开发使用到的一些UI组件.能够帮助企鹅仔高速对该平台微信开发有个了解. 本文介绍的微信硬件物联网开发思路不局限于某个平台.对市场上全部的平台,如机智云也是适用的,特此说明. 一.创建微信应用,配置微信server 在云智易开发平台中,开发人员须要在应用管理中创建一个微信应用,填写微信公众号的基本信息:APPID, APPS

一起学Google Daydream VR开发,快速入门开发基础教程一:Android端开发环境配置一

原文因涉及翻墙信息,被强制删除,此文为补发! 准备工作 进入Google Daydream开发者官网,开启准备工作,官网地址:https://vr.google.com/daydream/developers/ -------------------------------------------------------------------------------------------------------------------- Google Daydream开发者网址: https

移动端开发的知识系统介绍

移动端开发1. 移动端适配:http://suqing.iteye.com/blog/1982733http://www.douban.com/note/261319445/ http://www.woshipm.com/ucd/150207.html<meta name="screen-orientation" content="portrait"><!-- 强制竖屏 --><meta name="x5-orientatio

移动端开发用touch事件还是click事件

前端开发现在包含了跨浏览器,跨平台(不同操作系统)和跨设备(不同尺寸的设备)开发. 在移动开发的过程中,到底选取touch事件还是click事件?对了,请不要鄙视click,click在移动端开发用着也是不错的. 首先,我先说一下touch事件在开发中存在的两个问题: 1.touch事件在某些场景下存在点击穿透的问题. 2.touchstart事件时触摸屏幕就会触发,touchend事件是手指离开屏幕就会触发,而有时候,我们仅仅是只想滑动屏幕,却会触发这两个事件. 1问题的原因:移动端事件触发的