最终,用户感知的性能是唯一重要的性能。用户通过触摸、移动和语音向系统提供输入。作为回报,他们通过视觉、触觉和听觉感知输出。性能是系统响应用户输入的输出质量。
在所有其他条件相同的情况下,除了用户感知的性能(以下简称?UPP)之外,针对某些目标优化的代码在与针对?UPP?优化的代码竞争时会失败。例如,用户更喜欢每秒仅处理?1,000?个数据库事务的响应灵敏、流畅的应用程序,而不是每秒处理?100,000,000?个数据库事务的不稳定、无响应的应用程序。当然,优化其他指标并非毫无意义,但真正的?UPP?目标是第一位的。
接下来的几小节指出并讨论基本的性能指标。
响应性是指系统响应用户输入提供输出(可能是多个)的速度。例如,当用户点击屏幕时,他们期望像素以某种方式发生变化。对于此交互,响应度度量是点击和像素更改之间经过的时间。
响应能力有时涉及多个阶段的反馈。应用程序启动是一个特别重要的案例,下面将详细讨论。
响应能力很重要,因为当人们被忽视时,他们会感到沮丧和愤怒。您的应用程序每秒都会忽略用户,因为它无法响应用户的输入。
帧速率是系统改变向用户显示的像素的速率。这是一个熟悉的概念:每个人都更喜欢每秒显示?60?帧的游戏,而不是每秒显示?10?帧的游戏,即使他们无法解释原因。
帧速率作为“服务质量”指标很重要。计算机显示器的设计目的是通过向用户传递模仿现实的光子来“欺骗”用户的眼睛。例如,覆盖有印刷文本的纸张以某种模式将光子反射到用户的眼睛。通过操纵像素,阅读器应用程序以类似的模式发射光子来“欺骗”用户的眼睛。
正如你的大脑推断的那样,运动不是不稳定和离散的,而是平稳且连续地“更新”。(频闪灯很有趣,因为它们把它颠倒了,让你的大脑缺乏输入来创造离散现实的幻觉)。在计算机显示器上,更高的帧速率可以更忠实地模仿现实。
注意:人类通常无法感知?60Hz?以上帧速率的差异。这就是为什么大多数现代电子显示器都设计为以该速率刷新的原因。例如,对于蜂鸟来说,电视可能看起来不稳定且不切实际。
内存使用情况是另一个关键指标。与响应性和帧速率不同,用户不会直接感知内存使用情况,但内存使用情况非常接近“用户状态”。理想的系统将始终保持?100%?的用户状态:系统中的所有应用程序将同时运行,并且所有应用程序将保留用户上次与应用程序交互时创建的状态(应用程序状态存储在计算机中)内存,这就是近似值接近的原因)。
由此得出一个重要但违反直觉的推论:设计良好的系统不会最大化可用内存量。内存是一种资源,空闲内存是未使用的资源。相反,设计良好的系统已经过优化,可以使用尽可能多的内存来维护用户状态,同时满足其他?UPP?目标。
这并不意味着系统应该浪费内存。当系统使用的内存多于维护某些特定用户状态所需的内存时,系统就浪费了可用于保留某些其他用户状态的资源。实际上,没有系统可以维护所有用户状态。智能地将内存分配给用户状态是一个重要的问题,我们将在下面更详细地讨论。
这里讨论的最后一个指标是功耗。与内存使用情况一样,用户只能通过设备维持所有其他?UPP?目标的时间来间接感知电量使用情况。为了满足?UPP?目标,系统必须仅使用所需的最低功率。
本文档的其余部分将讨论这些指标的性能。
本节简要概述了?Firefox/Gecko?如何在所有应用程序的水平下对性能做出一般贡献。从开发人员或用户的角度来看,这回答了“该平台为您做什么?”的问题。
Web?平台提供了许多工具,其中一些工具比其他工具更适合特定的工作。所有应用程序逻辑都是用?JavaScript?编写的。为了显示图形,开发人员可以使用?HTML?或?CSS(即高级声明性语言),或使用元素提供的低级命令式接口<canvas>(包括WebGL)。SVG位于?HTML/CSS?和?Canvas?之间,它提供了两者的一些优点。
HTML?和?CSS?极大地提高了工作效率,但有时会牺牲帧速率或对渲染的像素级控制。文本和图像自动重排,UI?元素自动接收系统主题,并且系统为开发人员最初可能没有想到的某些用例提供“内置”支持,例如不同分辨率的显示或从右到左的语言。
该canvas元素直接提供像素缓冲区供开发人员使用。这为开发人员提供了对渲染的像素级控制和对帧速率的精确控制,但现在开发人员需要处理多种分辨率和方向、从右到左的语言等等。开发人员使用熟悉的?2D?绘图?API?或?WebGL(主要遵循?OpenGL?ES?2.0?的“接近金属”绑定)在画布上绘图。
Gecko?JavaScript?引擎支持即时?(JIT)?编译。这使得应用程序逻辑的执行能力与其他虚拟机(例如?Java?虚拟机)相当,在某些情况下甚至接近“本机代码”。
Gecko?中支撑?HTML、CSS?和?Canvas?的图形管道通过多种方式进行了优化。Gecko?中的?HTML/CSS?布局和图形代码减少了滚动等常见情况下的失效和重新绘制;开发人员“免费”获得这种支持。canvas当被绘制到显示帧缓冲区时,Gecko“自动”绘制的像素缓冲区和“手动”应用程序绘制的像素缓冲区最小化副本。这是通过避免会产生开销的中间表面(例如许多其他操作系统中的每个应用程序“后台缓冲区”)以及使用可以由合成器硬件直接访问的图形缓冲区的特殊内存来完成的。使用设备的?GPU?渲染复杂场景,以获得最佳性能。为了提高功耗,简单的场景使用特殊的专用合成硬件进行渲染,同时?GPU?空闲或关闭。
对于丰富的应用程序来说,完全静态的内容是例外,而不是规则。丰富的应用程序使用动态内容和animation效果transition。过渡和动画对于应用程序尤其重要:开发人员可以使用?CSS?通过简单的高级语法来声明复杂的行为。反过来,Gecko?的图形管道经过高度优化,可以有效地渲染常见动画。常见动画被“卸载”到系统合成器,系统合成器可以以高性能、节能的方式渲染它们。
应用程序的启动性能与其运行时性能一样重要。Gecko?经过优化,可以有效地加载各种内容:整个?Web!多年来针对此内容的改进,例如并行?HTML?解析、智能调度回流和图像解码、巧妙的布局算法等,也同样转化为改进?Firefox?上的?Web?应用程序。
本节适用于提出以下问题的开发人员:“如何使我的应用程序更快”?
一般来说,应用程序启动会被三个用户感知的事件打断:
第一个是应用程序首次绘制—?已加载足够的应用程序资源以绘制初始帧的点
第二个是当应用程序变得交互式时-?例如,用户可以点击按钮并且应用程序做出响应
最终事件是满载-?例如,当所有用户的专辑都已在音乐播放器中列出时
快速启动的关键是要记住两件事:UPP?才是最重要的,并且上面每个用户感知的事件都有一条“关键路径”。关键路径正是且仅是必须运行以产生事件的代码。
例如,要绘制应用程序的第一个框架,该框架在视觉上包含一些?HTML?和?CSS?来设置该?HTML?的样式:
必须解析?HTML
必须构建该?HTML?的?DOM
必须加载和解码?DOM?该部分中的图像等资源
CSS?样式必须应用于该?DOM
样式文档必须重排
该列表中没有“加载不常见菜单所需的?JS?文件”;“获取并解码高分列表的图像”等。这些工作项并不位于绘制第一帧的关键路径上。
这似乎是显而易见的,但为了更快地到达用户感知的启动事件,主要的“技巧”是仅运行关键路径上的代码。通过简化场景来缩短关键路径。
Web?平台是高度动态的。JavaScript?是一种动态类型语言,Web?平台允许动态加载代码、HTML、CSS、图像和其他资源。这些功能可用于通过在启动后一段时间“延迟”加载不必要的内容来推迟关键路径之外的工作。
另一个可能延迟启动的问题是空闲时间,这是由于等待请求响应(例如数据库加载)而引起的。为了避免这个问题,应用程序应该在启动时尽早发出请求(这称为“前端加载”)。然后,当稍后需要数据时,希望它已经可用并且应用程序不必等待。
注意:有关提高启动性能的更多信息,请阅读优化启动性能。
同样,请注意,本地缓存的静态资源的加载速度比通过高延迟、低带宽移动网络获取的动态数据要快得多。网络请求永远不应该成为应用程序早期启动的关键路径。本地缓存/离线应用程序可以通过Service?Workers实现。有关使用?Service?Worker?实现离线和后台同步功能的指南,请参阅离线和后台操作。
想要获得高帧率,首先重要的是选择合适的工具。使用?HTML?和?CSS?来实现大部分是静态的、滚动的、很少有动画的内容。使用?Canvas?实现高度动态的内容,例如需要严格控制渲染且不需要主题的游戏。
对于使用?Canvas?绘制的内容,开发人员需要达到帧速率目标:他们可以直接控制绘制的内容。
对于?HTML?和?CSS?内容,获得高帧速率的途径是使用正确的原语。Firefox?针对滚动任意内容进行了高度优化;这通常不是一个问题。但通常会牺牲一些通用性和质量来换取速度,例如使用静态渲染而不是?CSS?径向渐变,可以将滚动帧速率推至目标之上。CSS媒体查询允许这些妥协仅限于需要它们的设备。
许多应用程序通过“页面”或“面板”使用过??渡或动画。例如,用户点击“设置”按钮以转换到应用程序配置屏幕,或者“弹出”设置菜单。Firefox?针对场景的过渡和动画进行了高度优化:
使用大约与设备屏幕尺寸或更小的页面/面板
CSStransform和opacity属性的过渡/动画
遵循这些准则的过渡和动画可以卸载到系统合成器并以最高效率运行。
改善内存和电源使用与加速启动是一个类似的问题:不要做不需要的工作或延迟加载不常用的?UI?资源。请使用高效的数据结构并确保图像等资源得到良好优化。
现代?CPU?在大部分空闲时可以进入低功耗模式。不断触发计时器或保持不必要的动画运行的应用程序会阻止?CPU?进入低功耗模式。节能应用程序不应该这样做。
当应用程序发送到后台时,visibilitychange会在其文档上触发一个事件。本次活动是开发者之友;应用程序应该监听它。
以下实用技巧将有助于提高上面讨论的一个或多个应用程序性能因素。
使用?CSS?动画和过渡
不要使用某些库的animate()功能,这些功能目前可能使用许多性能不佳的技术(setTimeout()例如top/left定位),而是使用CSS?动画。在许多情况下,您实际上可以使用CSS?过渡来完成工作。这种方法效果很好,因为浏览器旨在优化这些效果并使用?GPU?顺利处理它们,同时对处理器性能的影响最小。另一个好处是,您可以使用标准化语法在?CSS?中定义这些效果以及应用程序外观的其余部分。
CSS?动画使您可以使用关键帧对效果进行非常精细的控制,您甚至可以观看动画过程中触发的事件,以便处理需要在动画过程中的设定点执行的其他任务。您可以使用:hover、:focus、?或轻松触发这些动画:target,或者通过动态添加和删除父元素上的类来触发这些动画。
如果您想动态创建动画或在JavaScript中修改它们,James?Long?已经为此编写了一个简单的库,称为CSS-animations.js。
使用?CSS?变换
无需自己调整绝对定位和摆弄所有数学运算,而是使用transformCSS?属性来调整内容的位置、比例等。translate或者,您可以使用、scale和的各个变换属性rotate。原因又是硬件加速。浏览器可以在?GPU?上完成这些任务,让?CPU?处理其他事情。
此外,转换还为您提供了原本可能不具备的功能。您不仅可以在?2D?空间中平移元素,还可以在三个维度上进行变换、倾斜和旋转等。Paul?Irish从性能角度深入分析了(2012)的好处。translate()不过,一般来说,您可以获得与使用?CSS?动画相同的好处:您可以使用正确的工具来完成工作,并将优化留给浏览器。top您还可以使用一种易于扩展的方式来定位元素——如果您使用和定位来模拟翻译,则需要大量额外的代码left。另一个好处是这就像在canvas元素中工作一样。
注意:translateZ(0.1)如果您希望在?CSS?动画上获得硬件加速,您可能需要附加转换,具体取决于平台。如上所述,这可以提高性能。当过度使用时,它可能会出现内存消耗问题。在这方面你做什么取决于你——做一些测试并找出最适合你的特定应用程序。
使用requestAnimationFrame()而不是setInterval()
调用setInterval()以假定的帧速率运行代码,这在当前情况下可能可行,也可能不可能。它告诉浏览器渲染结果,即使浏览器实际上没有绘制;也就是说,当视频硬件尚未到达下一个显示周期时。这会浪费处理器时间,甚至会导致用户设备的电池寿命缩短。
相反,您应该尝试使用window.requestAnimationFrame().?这会等到浏览器真正准备好开始构建动画的下一帧,并且如果硬件不会实际绘制任何内容,则不会打扰。此?API?的另一个好处是,当您的应用程序在屏幕上不可见时(例如,如果它在后台且某些其他任务正在运行),动画将不会运行。这将节省电池寿命并防止用户在夜空中咒骂你的名字。
作为老派、具有可访问性意识的?Web?开发人员,我们喜欢点击事件,因为它们还支持键盘输入。在移动设备上,这些速度太慢。您应该使用touchstartandtouchend代替。原因是这些没有延迟,不会导致与应用程序的交互显得缓慢。如果您首先测试触摸支持,也不会牺牲可访问性。例如,金融时报为此目的使用了一个名为fastclick?的库,您可以使用该库。
我们在?HTML?应用程序中发现的一个重大性能问题是,移动大量DOM元素会使一切变得缓慢——尤其是当它们具有大量渐变和阴影时。它有助于简化您的外观并在拖放时移动代理元素。
例如,当您有一长串元素(比如说推文)时,不要将它们全部移动。相反,只在?DOM?树中保留可见的推文以及当前可见推文集两侧的一些推文。隐藏或删除其余部分。将数据保存在?JavaScript?对象中而不是访问?DOM?可以极大地提高应用程序的性能。将显示视为数据的呈现,而不是数据本身。这并不意味着您不能直接使用?HTML?作为源代码;只需读取一次,然后滚动?10?个元素,根据结果列表中的位置更改第一个和最后一个元素的内容,而不是移动?100?个不可见的元素。同样的技巧也适用于游戏中的精灵:如果它们当前不在屏幕上,则无需轮询它们。相反,当新元素进入时,重新使用滚动到屏幕外的元素。
Firefox、Chrome?和其他浏览器包含内置工具,可以帮助您诊断页面渲染缓慢的情况。特别是,Firefox?的网络监视器将显示页面上每个网络请求发生的时间、大小以及需要多长时间的精确时间线。性能意味着效率。在开放?Web?应用程序的背景下,本文档一般解释了什么是性能、浏览器平台如何帮助改进性能以及可以使用哪些工具和流程来测试和改进性能。