前端优化思考

前端优化

2018-10-31

本文站在内核的角度为前端优化提供一些思路。

# 前言

Web强大的生命力,得益于它所推崇的一些革命性的思想, 无中心: 没有中央控制节点,可以自由的在网络发布任意内容。 无歧视:所有网络参与者可以平等的进行交流,不受操作系统,网络运营商,等等的影响。 自下而上设计: 鼓励大家参与和实验,而不是由一小部分专家编写和控制。 普遍性:所有人都可以在网络上发布任何东西,不受硬件,地理位置,信仰文化,等等的影响。 共 识:大家可以自由的参与规范的讨论,但必须遵循已形成标准的规范。 正是这种自由平等开放共享的精神,使得Web面对各种挑战,依然能一次又一次的焕发生机。 而在Web技术的应用过程中,我们往往会忽略这些内在的精神,更加关注一些更加具体的指标,比如性能指标。 在性能指标方面,前端往往缺乏非常精确的衡量手段,但几乎都会得出Web性能不如Native性能的结论。 然而事实真的如此吗,Web在各个方面都比不上Native吗? 从技术的角度来看,Native App可以直接运行在操作系统上,可以直接调用系统API,而Web App (or Page) 只能运行在基于内核的应用上,通过应用去调用系统API。 通过应用去调用系统API,这中间流程的性能损耗处于什么级别呢?很小,非常小,非常非常小,C++/Java代码执行的成本非常低,整个调用流程一般在毫秒级别。 那么,我们为什么会得出Web性能不如Native性能的普遍结论呢? 可能有下面几方面的原因: Web页面需要运行在应用之上,而应用的执行流程对前端来说是一个黑盒,在不了解这个黑盒的损耗的情况下,只好假定它的损耗是非常大的。 一些前端框架的性能并不理想,特别是一些框架的初始化特别耗时。框架的执行流程对前端来说也是黑盒,框架的性能也会笼统的认为就是应用的性能。 Web技术的使用方式灵活多样,不同的使用方式效果差别很大。一些Web技术使用不当,也可能会引入性能问题。 那么,怎样才能更好的使用Web技术呢?我们下面重点讨论一下,在进行前端优化时,我们可以有那些思路。

# 优化的基础

# 精确的指标衡量体系

我们在进行Web优化之前,首先要做一些基础的事情,比如,建立能准确体现用户体验的指标衡量体系。 如果衡量指标不精确,优化效果可能会与我们理想的目标背道而驰,甚至会出现指标表现一片大好,而用户却处于水深火热之中的情况。 在首屏性能指标体系方面,U4内核一直走在行业的前面,主要表现在: 行业内很多公司使用实验室数据作为指标数据时, 我们就早已使用真实用户统计数据作为指标数据。 在内核层面使用自有算法去计算首屏性能,精确度非常高,远高于Chromium的First Meaningful Paint。

iOS 未开放内核, 所有iOS上的应用只能使用系统内核,所以iOS上还未能实现U4内核的首屏性能指标。

出于多端指标统一的考虑,业务方往往会选择 WebViewClient.onPageFinished 或 PerformanceTiming.loadEventEnd 作为页面性能的衡量指标。 虽然这些指标不能很精确的衡量首屏性能,但也能成为多方可接受的折中方案。 目前U4内核也在与业务方一起建立一套统一的指标衡量体系,希望大家能在标准统一的情况下进行业务的优化。

# 明确约束条件

我们在进行Web优化时,需要明确一些约束条件,在满足约束条件下达到指标最优。 比如,我们使用loadEventEnd作为页面性能指标,但这个指标仅仅反映了资源加载的性能,并不能反映首屏渲染的性能,或者用户可交互的性能。 我们不能为了提升loadEventEnd,将所有的资源都优先加载,而阻塞了页面排版渲染。即需要在首屏性能(T2)不变差的前提下去优化loadEventEnd。 再比如,我们都知道,资源预加载到本地,将联网性能转化为本地性能是优化性能的重要手段。但是,预加载一般会存在使用率不高,服务器压力过大等等问题,即我们不能为了提升100ms的性能而让服务端增加100台服务器,而应该在服务器部署成本不提升的情况下去优化性能。

# 初级优化

我们在进行Web优化时,需要分阶段有步骤的进行。我们先聊聊初级优化。 初级优化,并不代表简单或者不重要,而仅仅代表它是其它优化的基础,有比较成熟的优化实践指导方案。 初级优化一般是指正确使用Web技术和前端架构,包含但不限于: 使用恰当的前端框架。 使用恰当的前端技术架构。 使用恰当的Web技术。 按规范使用Web技术。 正确使用Cache和压缩图片。 我们举了一些例子进行说明。 权威统计机构Http Archive的数据表明,所有页面的平均数据, 图片占页面大小的50%以上,其中压缩率比较高的WebP格式图片仅占1%, JPG+PNG+GIF图片占比96%。 过去,某业务使用了未经处理的PNG图片,甚至有大小超过5M的单张图片。 我们再看看Cache的数据,Cache有效期为0,即不能缓存的资源,占比50%。这个比例是非常惊人的,即平均每个站点有一半的资源是不能缓存的。 这些看似简单基础的事情,大部分页面都没有做或者没有做好,会严重影响页面的性能和用户体验。 我们再聊聊前端框架,在使用前端框架时,需要先了解它的性能,特别是初始化性能。 举个例子,某业务,使用的JavaScript执行耗时可超过1.5秒,主要是框架的初始化耗时, 各种前端框架都有它的初始化成本,我们一般需要选择合适自己业务要求,性能又还可接受的框架。 出于各种原因,比如一些历史原因,或者业务原因,我们很可能选择了性能较差的框架,我们也需要了解它的详细性能数据,做到心中有数。

# 中级优化

中级优化,一般是指结合业务场景,灵活使用数据和工具,定位和解决页面存在的问题。 各种页面在各类业务场景下,存在的问题往往都不一样,需要具体问题具体分析。 但分析问题的方法或手段都是相通的,包含但不限于: 综合分析用户数据,挖掘问题。 灵活使用Chrome Devtools 开发调试工具, 调试页面和定位问题。 灵活使用 Lighthouse,检测页面和解决问题。

用户数据,是真实反映用户实际情况的。用户数据的分析也非常有讲究,各种分析维度都会得出各种结论,要合理的使用恰当的分析维度。 比如,用户手机系统,网络类型,地理位置,等等。 Chrome Devtools 开发调试工具 是前端开发调试神器,里面包含的功能非常强大,几乎能分析所有前端的疑难问题。 我们提取一些特色功能进行介绍,

  1. Timeline Timeline可以记录页面运行过程的所有细节,能用于分析页面出现问题的具体位置。 举个例子,某业务,在页面改版之后,页面首屏渲染时间变长200ms。 改版前的Timeline是这样的: 1.png 改版之后的Timeline是这样的: 2.png 原因是一些期望在首屏之后执行的JS逻辑,在首屏之前就被执行了,从而延后了首屏的渲染时机。 出现问题的代码:
_article.main(function() {
          _article.fsTime();
          cb && cb()
        });

修改也很简单,将一些非首屏的渲染逻辑延后一些执行:

_article.main(function() {
          _article.fsTime();
          setTimeout(cb,20);
        });

当然, 上面只是使用Timeline的一个简单例子,与页面执行时序相关的问题,都可使用它协助分析。它的更多优秀功能,需要大家自己去探索发现。 2. Profile Profile 也是一款很强大的分析工具,它可以分析页面的内存使用情况和JS/CSS执行时间。 一般地,我们可以使用Timeline定位出现问题的大概位置,再使用 JavaScript CPU profiler 详细分析每个JS函数的执行情况,找到具体的问题点。 3. Chrome Trace Chrome Trace 数据记录了页面在浏览器内核执行的完整过程,粒度精细到每个函数方法。使用Trace数据可以分析页面在浏览器内核执行的细节。 根据Trace信息,可以很准确的定位具体的问题,前提是前端同学能够理解具体的函数方法在浏览器内核中的含义,所以对前端的要求是非常高的。 正因为Trace分析对前端的要求过高,Chrome又推出了基于Trace的分析工具Lighthouse。Lighthouse能根据特定的模型用例,得出前端易懂的分析结果。 比如,它可以检测页面是否符合PWA的要求,分析页面在关键路径的耗时。 U4内核针对Lighthouse进行了扩展,开发了鲁班尺工具,能够更加全面准确的分析前端关注的问题,比如,它能分析页面JS执行的总体耗时,超过50ms的JS执行函数,页面缓存命中情况,LocalStorage使用情况,排版渲染执行情况,等等

# 高级优化

前面讨论的优化,主要参与者是前端,主要受益者是分析者自己的页面。更高级的优化应该是怎样的呢? 高级优化一般是指全链路拉通进行优化,优化前端页面/框架,后端服务器/中间件,内核,图床,等等,并将优化结果集成到工具,形成自动化检测案例。 我们先来看为什么全链路拉通很重要。每个端(前端,后端,中间件,图床,内核,等等)都有自己的视角,很难看清楚整个链路的问题。 而页面性能问题可以发生在链路的任意一个节点,问题的解决方案在各端都有区别,通过全端拉通我们可以选择最优的解决方案。 举一些例子, 在某业务优化过程中,我们多端拉通得出了一个首屏图片预加载的方案,改动涉及到页面,服务器端,图床,应用客户端,最终提升整体性能近300ms。 在某业务优化过程中,我们与客户端,网络库,多端拉通,最终分析出客户端和网络库存在性能问题,修正问题后带来较大提升。 在某业务优化过程中,我们与页端,运营端,多端拉通,最终分析出运营一些配置使得页面文档无法缓存,而这个问题是可以避免的。 这样的例子还有很多,都说明了多端拉通在性能优化中具有非常重要的作用。 多端拉通进行优化,我们的视角更加全面,解决问题的思路也更加开阔。选择在最合适的端进行解决问题,解决问题的方法不再局限于修改前端页面。 我们也可以加强U4内核与前端的交流合作,在内核或前端框架层面,进行更加高效的优化。 前面也提到,一些前端框架的性能并不理想,我们期望与前端合作,一起去优化一些流行的前端框架的性能。 页面优化,通常属于一种补救手段,而不应属于一种常态,我们不期望同一页面的性能需要反复优化。 我们期望一些优化成果能够固化到工具层面,通过工具自动化去监测页面性能,让工具去保障页面能够持续具备优异的性能。这也是我们鲁班尺的思路。

# 展望未来

前面重点讨论了前端优化的一些思路,我们再回到Web技术发展前景的问题。 Web技术所推崇的自由平等开放共享的互联网精神,得到了全世界的普遍认可。在Web技术发展之初,就由万维网发明人Tim Berners-Lee 带领成立了万维网联盟(W3C理事会)。W3C致力于构建广泛参与的、知识共享的、具有信任的全球规模的Web。目前W3C成员已经有超过400个研究机构或组织,其中包括Apple, Inc.,Google, Inc.,Microsoft Corporation 等全球顶级科技公司。有成千上万的科学家参与Web标准规范的制定和实现,我们有充分的理由相信Web技术的长远发展是有坚实的技术和人才保障的。 回顾历史,PC年代早期,大家都去下载Windows软件,随着PC电脑的不断进化,网络带宽的不断增强,现在大家很少会下载PC软件,基本以浏览器为主。 移动互联网时代也是一样,目前手机内存3G及以上的占比已超过50%,WIFI+4G网络占比已超过90%,手机处理能力和网络带宽已不是Web技术的瓶颈。 Google Chrome 在2014年推出PWA系列技术,给前端开发者全面开放浏览器的底层能力,包括但不限于,消息推送通知,拦截资源请求,管理资源缓存,添加到主屏幕,在合成器线程上同步运行用户代码,等等。 近期,苹果公司在2018年初就支持了ServiceWorker的基本能力。相信在不久的将来,主流浏览器都会全面支持PWA相关技术,届时,前端能在Web上面发挥的空间会越来越大。 Web技术的繁荣发展,需要每一个开发者的共同努力,包括前端,内核,服务器。特别是前端开发者,前端每一次技术选型,每一个页面取得的效果,都与Web技术发展息息相关。U4内核期望与前端开发者紧密联系,共同努力打造极致的Web体验。