自从 html5 诞生之后,关于 Web App 和 Native App 的讨论就从未间断过,孰优孰劣大家各执一词。但作为前端开发者的我们,心里其实是明白的,这个世界是你们的(Native App),也是我们(Web App)的,但终究还是我们的,如果几十年后再回头看这一路的话,会发现你们不过是一插罢了。哈哈哈哈哈哈
但现在摆在眼前的事实是,Native App 比 Web App 的市场大,大家更愿意去用 Java 或者 OC ,而不愿意用 Js。大家都不喜欢用 Web App ,究其原因无非就两点:兼容性、慢。
那我们就来谈谈慢这个问题。但貌似这个问题很庞大,这里就谈一些我了解的东西。
提高页面加载速度,这个问题老生常谈了,什么多域名、CDN、组件化、seajs都是解决办法,淘宝首页就是个很好的案例。这里我们就不再赘述,网上很多其它相关的资料。
动画才是我们今天要谈论的主要内容:如何做到 60fps。
60pfs 这是CRT显示器的刷新频率,也是人眼感觉不到卡顿的频率,也就是每秒 60 帧,每帧的时间间隔是 16ms。然后我们了解一下浏览器的渲染机制,计算机需要在 16ms 内完成下面这些任务:
- 计算 Js
- 浏览器计算 layout
- 绘图 paint
- 在 GPU 上拼合图层 composite
第一步 JS 计算是由开发者控制的,在这里的操作会影响到下面三步。在前端性能上我们经常遇到的问题就是回流,这就是由于开发者调用了一些方法触发了 layout,然后浏览器就接着 paint、composite。
所以在做动画的时候,不要用 JS 做计算密集型的任务,jQuery 返回的对象做好缓存,避免多次调用。layout 能不触发就不触发,paint 能不触发就不触发。那怎么做才能只触发 composite 呢? opacity
和 transform
这两个属性是不会触发 layout 和 paint 的。所以作为前端开发,我们很喜欢也很乐于做透明度淡入淡出,因为这个不会用太大的性能问题。
有的同学就要问了:咦?color 和 box-shadow 这些也不涉及到 layout 啊,那我可以大规模的运用吗?
答案是不行,为什么呢?因为在 layout、paint 和 composite 中,最消耗性能的就是 paint。具体有多消耗呢?
上面是我打开一个带有视差滚动效果的 medium 页面后,从上向下滚动时产生的数据,其中绿色部分就是 paint + composite。可以看到在桌面上,视差滚动勉强达到 60fps,这样的性能在手机上肯定是惨不忍睹的。其实在视差滚动中,元素的颜色大小位置都没有改变,理论上是不需要 repaint 的,那么如何才能避免它呢?
其中一种方法就是创建新的 layer,但这种方法有一定的代价,其中最出名的就是在高 DPI 屏幕下字体显示问题,还有子元素position:fixed
错位等等一些事情。
上面的图片就是在 surface pro3 + chrome 访问 feedly 的截图,可以明显的看到文字发虚。
日子还是要过的,Native App 也是要被打败的,那么怎么办呢?
Flipboard 开发团队就发明了一种丧心病狂的办法:用 canvas 渲染。Canvas 直接与 GPU 打交道,渲染速度非常快。但在使用过程中还是有很多顾虑的,下面是会遇到的一些问题:
- 文字换行如何处理
- 图片需要加载后才能放入 canvas
- 元素层级如何处理
- 自定义字体
- 如何排版
尤其是排版问题,CSS已经很成熟了,自己创立其它机制来排版无疑是搬石头砸自己的脚。所以 Flipboard 开发小组就将 DOM 和 Canvas 合二为一,利用 DOM 的排版优势和 Canvas 的渲染优势。
现在用手机访问 Flipboard 就可以看到他们的这一成果了,其方法就是文档结构按照正常的 DOM 来,但是不加任何的颜色样式,然后把这一层透明度改为 0 。在其上层再加入一层 canvas ,用来显示渲染的结果。效果还是很不错的:
总的来说,未来还是很光明的,虽然 web app 有各种各样的性能问题,但它还是向着越来越好的方向发展。只要我们合适的利用浏览器给我们的资源,我们还是可以做出优秀的效果的。
参考文章:
参考视频: