TAT.Kinvix HTML5 的性能优化分析
In Web 前端资讯 on 2012年07月02日 by view: 10,198
10

从性能角度来说,HTML5 首先是缩减了 HTML 文档,使这件事情变得更简单。

  • 第一,从用户可读性上说,原先一大堆东西,像初学者第一次看到这些东西是看不懂的,而 HTML5 的声明方式对用户来说显然更友好一些。
  • 第二,文档编码的声明,用 HTML5 方式的话,就很简单。

很多人问 HTML5 是什么?我们说可以先用 HTML5 的方式就是把 DOCTYPE 先改了,因为目前很多页面都还是用传统的方式。HTML5 的方式,本身是兼容 IE 浏览器的,从 IE6 到 IE10 都可以,包括高级浏览器都支持。所以说拥抱 HTML5 最简单的方式就是把 DOCTYPE 给改了。

 

1. 更简洁的标签

接下来可能并不是一件很常见的事情,但是却是我比较推崇的,使用更简洁的标签方式。HTML5 从这个名字大家可以听出,它是从 HTML4 继承过来的。HTML4 里面有严格模式跟过渡模式,HTML5 是支持这种过渡模式的,就是你可以不把一些标签闭合。但是,我并不推荐所有的标签,比方说 BODY 标签的不闭合,这种我们不推荐。但是像 P 标签最常用的,还有列表标签 LI。为什么这样说?首先从视觉的角度来说,这样的方式更简洁一点。然后关键的是在文档传输过程中,内容会更少。

HTML5 标签属性的声明支持三种方式:单括号、双括号和不加括号。为了减少文档大小,我是选择不加双引号的方式或单引号的方式。但是要注意,假设是类属性的声明,因属性可能包括多个类,多个类的时候则必须用括号括起来。在这方面,给大家看一下谷歌的一个实践。谷歌自己有一个页面完全实践了上面的东西,文档的大小减少了 20%,使 HTML 文档的传输减少了 20%。如果把整个都实践起来,可以达到 5%—20% 之间的减少。这是第一步,缩减 HTML 文档的大小。

2. 图片优化

接下来是关于图片的优化,图片永远是又爱又恨的元素。因为当图片多的时候,会严重拖垮整个页面的加载速度。关于图片的优化方式,《高性能网站》书中已有很多介绍,总结起来主要有三点:使用精灵图、优化图片的大小,使用 DATA URI,具体这里就不细说了。

图片优化的另一个思路是:no-image。抛弃图片,拥抱 CSS3。原先需要设置一张圆角效果的图片,现在使用 CSS3 中的 border-radius;原先需要设置阴影效果的图片,现在使用 CSS3 中的 box-shadow;原先需要设置渐变的背景图片,现在使用 CSS3 中的 gradient。

3. 预取

接下来讲 Prefetching,预取,是优化的另一个思路。我们现在优化的思路无非就是少。很多都是从少的角度,比方说前面把文档大小减少,把图片的大小减少。很多张的图片变成一张精灵图,都是为了把发送请求的数量减少。预取的话,是另一种思路,提早加载好资源,用户去点的时候,实际上已经加载好,那肯定是更快了。

预取,一共有两部分:一部分是资源的预取,还有一部分是 DNS 的预解析。

资源预加载有几个点需要注意:

预加载只是在浏览器空闲的时候才会去拉,但不保证一定会去拉,这是很重要的一点。因为本身浏览器有一个全局的监听器,这是内部的一个接口,当浏览气空闲的时候,它会去执行浏览器空闲的时候应该做事情,但是这个空闲的回调不一定被触发,所以说并不保证一定会执行预加载。

Chrome 不支持 HTTPS 资源的预加载,像 Alipay 是 HTTPS 的页面,Chrome 不会去预拉取。

一个预拉取的页面虽存在后不可见,实际上它是在正常解析。假如说我预拉取登陆页面,登陆页面有很多资源,比方说有图片,有 CSS 文件,JS 文件。它是从上往下正常的会被解析,解析的过程中,这个页面没有显现,但是它实际上是存在的。在 HTML5 里面,可通过 document.visibilityState 得到当前页面状态,通常页面有两种状态,可见与不可见,但是现在有一个新的状态,叫做预渲染的状态。可以直接通过 document.visibilityState 是否等于 prerender 来判断页面是否在预渲染状态。

4.DNS 解析

接下来是关于 DNS 的解析。有时候我们登入页面,对用户可能点的地方相对而言是比较难探测到,当然有时候我们会做一些埋点来探知用户下一步行为大部分是往里走。但有些情况下,我们不知道用户下一步具体会走到哪一个页面的时候,但是我们知道他要走到哪一个域。这个时候,我就可以预解析 DNS。因为实际上,整个页面的请求过程中间有一个很长的 DNS 的解析过程,如果说这个我们提前做了,就可以更进一步让用户看到这一页面。

以下是 Q+壁纸的案例。Q+壁纸是 Q+某一个系统系统,首先 Q+整个的架构是基于 WEB + 客户端。我们现在看到的就是一个 WEB 的页面,虽然它外面是一个客户端的壳,但是它的心是 WEB 的。整个过程在我们第一次在完成的时候,因为图片比较多,所有的静态资源是分配到十几个静态服务器上。也就是说,如果我要去拉的时候,我就要解析 10 个 DNS,这个时间是相当耗时的,最慢的时候可能会延迟几秒钟,这是我们肉眼能感觉到的。如果进行 DNS 预解析,因为本身资源我不知道具体是哪一个,所有图片都是随机的,所以我们只能说在 DNS 预解析上下功夫,来提升它的速度。这样的话,从原来可能需要 2 秒钟,我就变成 1 秒钟。

接下来讲 Q+中的应用。我们会像 QQ 里面一样,QQ 里面跟 Q+都有很多文字链,就是窗口的左下角有一个文字 APP 信息的推送。这边是通过 WEB 时时去拉取后端,后端拉取过来然后在前台显示。但是在某一个时期,其实所有的 APP 它一共推送的运营信息是固定的。如果说按某个具体 APP 去分析每个文字链对应数组的话,这个时候是非常大数据。因为这里一个就大概有达到三四百个字节,从优化的角度说,我们把这些每次拉区过来的存在本地。再存上本地的 localStorage,我们是同一域,所有的 APP 之间的信息都是可以相互访问的。然后就是把所有拉过的 ID,就不会再重新拉一遍。

在这里也有一个需要注意的点,localStorage 目前很多厂商的实现是同步的。如果你大量地调用 localStorage 这个接口,实际上他会阻塞你的渲染进程。这个时候,当用户往下拖动页面的时候,然后你这个时候又正好在做存储数据,这个数据又比较大,这个时候用户就会感觉你这个页面非常卡。之前他们都有讨论这个问题,本身这个接口的设计 IE 是设计成异步的,他们设计是成同步。这个会导致在调这个借口的时候,假设你程序比较多,因为有一个序列化的过程,序列到磁盘。这样的话,整个过程就会显得比较慢。再加上本身 localStorage 可以做不同的窗口之间共享这个数据,它会在这个数据上加锁。如果大量地数据在调用这个本地接口,它就会显得比较卡。所以目前没有什么特别好的解决方案,但是这是需要记住的。即使说目前最大的五点多兆,如果你用了五点多兆,会让用户很悲催。因为你如果一去调用这个借口,用户在拖用鼠标,就觉得非常卡。

5. 离线存储

接下来讲离线存储在性能方面给用户带来的好处。首先是进离线存储的定义文件,在 Q+中所有的系统模块,都是有定义离线支持。就是说所有的应用,如果网断了,还是可以用。在文档中加入 MANIFEST 的文件,MANIFEST 是一个定义文件,声明当前页面哪些是需要存储在本地的?哪些是不需要存储的?哪些如果说请求失败,应该用哪些新的图片或者什么来代替?这样分三块:

第一,CACHE,哪些需要存储到本地。

第二,NETWORK,是不会存储在本地的,它每次都回去请求一遍但是这里需要指出的是,本地存储跟浏览器存储实际上是两回事情,他们存的是两块不同的地方。即使 NETWORK 这边需要告诉 APP 说,我需要每次都拉一次,因为像 Chrome,他这个存储缓存是非常可恶的,比较难清除的,必须通过手动去清除,才能完全生效。所以说你即使设置了不要让它存储在本地,但是浏览器可能本身把它存储起来了,因为他存的是两块不同地方。

第三,FALLBACK。如果说一个图片假如说请求失败,它是 404。那要用什么图片代替?我觉得这个比较好玩。

MAEIFEST 怎么设置? MANIFEST 这里需要注意的是三点:

MANIFEST 同源限制;

MIME 类型必须为 text/cache-manifest,这是标准的,如果是其他格式,都不会生效;

CHROME,如果要看这个东西有没有生效,可能通过 CHROME 这个伪协议的方式在浏览器输入,chrome://appcache-internals。

关于如何去更新应用的缓存。为什么要离线存储?离线存储在本地,当浏览器知道你有离线存储你,它会首先去离线存储的目录下,去找这个资源是否已经被 Cache。当它已被 Cache 的时候,他就直接从这边拿到这个资源,不会再去发送一个请求。因为浏览器的请求是这样的,当有离线存储的话,就连请求都不会发,所以说会更快。 如果说有的时候我们需要更新,更新的时候怎么办?

用户可以手动去清除浏览器的 Cache,这个时候自动把本地存储给清除了。

修改 MANIFEST 的任何内容,这是比较推荐的方式,也是我们线上用的方式。就是说我们可以修改里面的的具体项目,但是这里应该最好是修改注释,因为我每次发布的时候,我们自动发布机制,发布的时候在上面注释修改一下就可以了。这样的话,每次发布的内容,都会实时同步到客户端的本地;

通过程序去执行,程序的就是 window.applicationCache.update()。就是我要去操作离线存储,其实我有时候叫应用存储,因为它的语意就是应用存储。我们去手动的更新应用存储。

6.Web Worker

接下来 Web Worker。 Web Worker 是一个多线程的 JS 进程。应用场景其实我们在线上的话,是没有的,我就不讲了。但是可以讲下具体我看到过的应用场景。

首先介绍一下 WEBWORK 是什么东西?它是一个 OS 级别的线程。之前我们模仿多线程,实际上都是多开一个窗口。但是现在的话,浏览器本身就提供了,这个会让操作带来更多便利,是让我们整个文档比较重,并不是很建议的方式。

然后 WebWorker 访问能力是有限的,它并不能访问到很多全局对象。比如说 documnet 对象它是访问不了的。 WebWorker 最适合的场景就是 CPU 密集型的计算操作。之前我们做游戏的时候,我们用 BOX2D。应该很多人听到过,它涉及到大量的计算,就是整个页面里面,下面所有的物体要去计算它们的碰撞关系,这个计算量是非常大的。但是如果放在当前的 JS 的进程里面去执行,这个计算量一大,一计算,整个页面就非常卡。但是如果用 WebWorker 去做,它是异步的过程,实时的发送过去,在计算的过程中还能干其他事,这就是多线程。

7. 设备 API

讲一下设备 API。设备 API 我觉得最重要在性能方面,也是目前实现最早的 API。一个是 CONNECTION,就是网络带宽。这个有什么作用?在中国这个场景下,必须得记住,很多用户的网速依旧是很低的。我们希望让用户网速低的时候,能够自动降级到一个比较低的方案。如果用现有的技术,我们是做不到的。但是使用设备 API 我们是可以的。因为我们知道,从设备上可以取到这些信息。它的宽带是多少,多少宽带的时候我们能干的事情。比方说宽带好的时候,我就用高清图片。宽带比较低的时候,就用清晰度比较低的图片。

8. 电池

下面一个是关于电池的。我觉得从性能角度来说,主要是电量方面。假如说用户电池电量比较低的时候,我觉得是应该尽量少做一些事情。本身手机现在电池的技术来没有突破,我觉得让 APP 看起来比较高性能,也是一个宣传亮点。

9.CANVAS

接下来是 CANVAS。讲 CANVAS 的几个性能优化点,用了这些东西,性能会有 10 倍的提升。

第一,每个 CANVAS 就是一个画布,我们要去渲染一个图形的时候, 我们是可以把它分层的。就是像 PS 里面一样,是一层两层三层。很多用户在做游戏的时候,直接把所有东西仿放到一个层里,一更新所有的东西都要更新。但如果你把它分层,你让背景放在背景层,角色放到角色层。这样的话,我要更新角色的时候,只会更新角色,背景层不需要变。让 CPU 干的事情更少了,性能自然而然就提升了。

第二,context.drawImage。不要去缩放图片,我们一开始就犯了一个错误,我们的美工做的图片始终跟我们不一致,然后我们要去缩放图片。因为本身设备它的图片大小是这样的,我们必须按比率缩放图片。缩放图片以后发现在低端设备下,比方说 iPad 或者 iPhone 就会非常卡,我们就想为什么?就进行代码上的分析,当用这个方法时候,花费的时候特别多。

第三,requestAnimationFrame。这是专门为渲染优化的一个方法。它本身的原理是这样的,当浏览器每过一桢的时候,会触发这个方法,当我在触发的时候,Canvas 得到这个浏览器已经准备好做下桢的事情。如果用传统的方法,是不会去考虑你更多的东西,它只会知道我过了多少时间,我就要执行。假如说用户之前被阻塞了,每 10 秒钟执行这一方法,在 10 秒之内,实际他之前的事情还没有做完,然后这个事情就会被延后。它就是为了动画看上去更流畅而优化的,因为每一桢的时候,它就告诉你说,你可以做一些事情。

Via:InfoQ

原创文章转载请注明:

转载自AlloyTeam:http://www.alloyteam.com/2012/07/html5-performance-optimization-analysis/

  1. HTML5的性能优化分析 | 老魏的工作笔记 2014 年 5 月 6 日

    […] 原文出处:腾讯 Web 前端 AlloyTeam 团队 Blog […]

  2. lawine 2013 年 11 月 12 日

    canvas 分层以后,如果想右键保存图片的时候,就瞎了

  3. yanhaijing 2013 年 10 月 24 日

    这个写的还不错

  4. HTML5的性能优化分析_WEB开发家园 2012 年 10 月 10 日

    […] 原文链接 Posted in WEB 前端 Tagged HTML5 更多 document.getElementById("bdshell_js").src = "http://bdimg.share.baidu.com/static/js/shell_v2.js?cdnversion=" + new Date().getHours (); […]

  5. myhere 2012 年 7 月 13 日

    ding

  6. choizhang 2012 年 7 月 3 日

    请问在预加载里面,我用 fiddler 测试,firefox 在原页面加载的时候预加载了资源,chrome 没有,不知道怎么回事啊,怎么测试加载带来的性能优化?

    • TAT.iAzrael

      azrael 2012 年 7 月 5 日

      跟 chrome 的版本有关吧,有些版本不支持预加载。

      • choizhang 2012 年 7 月 9 日

        o , 我是 19,后来测试发现只是没有显示而已,确实是已经加载到本地缓存了。

  7. mxclion 2012 年 7 月 2 日

    好文!

  8. HTML5性能优化分析 « Dave Liang {q} 2012 年 7 月 2 日

    […] 转自 : http://www.alloyteam.com/2012/07/html5-performance-optimization-analysis/ […]

发表评论到 mxclion