从性能角度来看(至少),service worker 最重要的优势之一是它们能够主动控制资源的缓存。可以缓存所有必要资源的 Web 应用程序对于回访用户来说加载速度应该会明显更快。但是这些提升在实际用户眼中是什么样子的?又该如何衡量呢?
Google I/O Web 应用程序(简称 IOWA)是一个 渐进式 Web 应用程序,它利用了 service worker 提供的大部分新功能,为其用户提供了丰富的、类似应用程序的体验。它还使用了 Google Analytics 来捕获来自其庞大且多样化的用户群的关键性能数据和使用模式。
本案例研究探讨了 IOWA 如何使用 Google Analytics 来回答关键性能问题,并报告 service worker 的实际影响。
从问题开始
每当在网站或应用程序中实施分析时,重要的是首先确定您试图从将要收集的数据中回答的问题。
虽然我们有几个想要回答的问题,但为了本案例研究的目的,让我们重点关注其中两个更令人感兴趣的问题。
1. Service worker 缓存是否比所有浏览器中现有的 HTTP 缓存机制更有效?
我们已经预料到,对于回访用户来说,页面加载速度比新访用户更快,因为浏览器可以缓存请求并在重复访问时立即提供它们。
Service worker 提供了替代的缓存功能,使开发人员可以精细地控制缓存的内容和方式。在 IOWA 中,我们优化了 service worker 的实现,以便缓存每个资源,这样回访用户就可以完全离线使用该应用程序。
但是,这种努力会比浏览器默认执行的操作更好吗?如果更好,又会好多少? 1
2. Service worker 如何影响网站加载的体验?
换句话说,无论传统页面加载指标衡量的实际加载时间如何,网站加载感觉有多快?
回答关于体验感受的问题显然不是一件容易的事,而且没有任何指标能够完美地代表这种主观情绪。话虽如此,但肯定有一些指标比其他指标更好,因此选择正确的指标非常重要。
选择正确的指标
默认情况下,Google Analytics 会跟踪 1% 的网站访问者的页面加载时间(通过 Navigation Timing API),并通过“平均页面加载时间”等指标提供该数据。
平均页面加载时间 是回答我们第一个问题的好指标,但它不是回答第二个问题的特别好的指标。首先,load
事件不一定对应于用户实际可以与应用程序交互的时刻。此外,加载时间完全相同的两个应用程序可能感觉加载速度大相径庭。例如,带有启动画面或加载指示器的网站可能比仅显示空白页面几秒钟的网站感觉加载速度快得多。
在 IOWA 中,我们展示了一个启动画面倒计时动画,(在我看来)它非常成功地在应用程序的其余部分在后台加载时娱乐了用户。因此,跟踪启动画面出现的时间作为衡量感知加载性能的一种方式更有意义。我们选择了首次绘制时间指标来获取此值。
一旦我们确定了想要回答的问题并确定了有助于回答这些问题的指标,就该实施 Google Analytics 并开始衡量了。
分析实施
如果您以前使用过 Google Analytics,那么您可能熟悉推荐的 JavaScript 跟踪代码段。它看起来像这样
<script>
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
ga('create', 'UA-XXXXX-Y', 'auto');
ga('send', 'pageview');
</script>
<script async src="https://#/analytics.js"></script>
上面代码中的第一行初始化了一个全局 ga()
函数(如果它尚不存在),最后一行异步下载 analytics.js
库。
中间部分包含这两行
ga('create', 'UA-XXXXX-Y', 'auto');
ga('send', 'pageview');
这两个 命令 跟踪访问您网站的人员访问了哪些页面,但 除此之外不多。如果您想跟踪其他用户互动,则必须自己进行。
对于 IOWA,我们想跟踪另外两件事
- 页面首次开始加载到屏幕上出现像素之间经过的时间。
- service worker 是否正在控制页面。有了这些信息,我们可以细分我们的报告,以比较有 service worker 和没有 service worker 的结果。
捕获首次绘制时间
某些浏览器会记录首次将像素绘制到屏幕上的确切时间,并将该时间提供给开发人员。该值与通过 Navigation Timing API 公开的 navigationStart
值进行比较,可以非常准确地计算出用户最初请求页面到他们第一次看到内容之间经过了多少时间。
正如我已经提到的,首次绘制时间是一个重要的衡量指标,因为它是用户体验您网站加载速度的第一个点。这是用户获得的第一印象,良好的第一印象可以对用户体验的其余部分产生积极影响。2
为了在公开首次绘制时间的浏览器中获取该值,我们创建了 getTimeToFirstPaintIfSupported
实用程序函数
function getTimeToFirstPaintIfSupported() {
// Ignores browsers that don't support the Performance Timing API.
if (window.performance && window.performance.timing) {
var navTiming = window.performance.timing;
var navStart = navTiming.navigationStart;
var fpTime;
// If chrome, get first paint time from `chrome.loadTimes`.
if (window.chrome && window.chrome.loadTimes) {
fpTime = window.chrome.loadTimes().firstPaintTime * 1000;
}
// If IE/Edge, use the prefixed `msFirstPaint` property.
// See http://msdn.microsoft.com/ff974719
else if (navTiming.msFirstPaint) {
fpTime = navTiming.msFirstPaint;
}
if (fpTime && navStart) {
return fpTime - navStart;
}
}
}
有了这个,我们现在可以编写另一个函数,该函数 发送 一个 非互动 事件,其中首次绘制时间为其值:3
function sendTimeToFirstPaint() {
var timeToFirstPaint = getTimeToFirstPaintIfSupported();
if (timeToFirstPaint) {
ga('send', 'event', {
eventCategory: 'Performance',
eventAction: 'firstpaint',
// Rounds to the nearest millisecond since
// event values in Google Analytics must be integers.
eventValue: Math.round(timeToFirstPaint)
// Sends this as a non-interaction event,
// so it doesn't affect bounce rate.
nonInteraction: true
});
}
}
在编写完这两个函数之后,我们的跟踪代码如下所示
// Creates the tracker object.
ga('create', 'UA-XXXXX-Y', 'auto');
// Sends a pageview for the initial pageload.
ga('send', 'pageview');
// Sends an event with the time to first paint data.
sendTimeToFirstPaint();
请注意,根据上述代码的运行时间,像素可能已经或可能尚未绘制到屏幕上。为了确保我们始终在首次绘制发生后运行此代码,我们将对 sendTimeToFirstPaint()
的调用推迟到 load
事件之后。实际上,我们决定推迟发送所有分析数据,直到页面加载完毕,以确保这些请求不会与其他资源的加载竞争。
// Creates the tracker object.
ga('create', 'UA-XXXXX-Y', 'auto');
// Postpones sending any hits until after the page has fully loaded.
// This prevents analytics requests from delaying the loading of the page.
window.addEventListener('load', function() {
// Sends a pageview for the initial pageload.
ga('send', 'pageview');
// Sends an event with the time to first paint data.
sendTimeToFirstPaint();
});
上面的代码将 firstpaint
时间报告给 Google Analytics,但这只是故事的一半。我们仍然需要跟踪 service worker 的状态;否则我们将无法比较 service worker 控制的页面和非控制页面的首次绘制时间。
确定 service worker 状态
为了确定 service worker 的当前状态,我们创建了一个实用程序函数,该函数返回三个值之一
- controlled:service worker 正在控制页面。在 IOWA 的情况下,这也意味着所有资源都已缓存,并且页面可以离线工作。
- supported:浏览器支持 service worker,但 service worker 尚未控制页面。这是首次访问者的预期状态。
- unsupported:用户的浏览器不支持 service worker。
function getServiceWorkerStatus() {
if ('serviceWorker' in navigator) {
return navigator.serviceWorker.controller ? 'controlled' : 'supported';
} else {
return 'unsupported';
}
}
此函数为我们获取了 service worker 状态;下一步是将此状态与我们发送到 Google Analytics 的数据关联起来。
使用自定义维度跟踪自定义数据
默认情况下,Google Analytics 为您提供了多种方法,可以根据用户、会话或互动的属性将您的总流量细分为多个组。这些属性称为维度。Web 开发人员关心的常见维度包括 浏览器、操作系统 或 设备类别。
Service worker 的状态不是 Google Analytics 默认提供的维度;但是,Google Analytics 确实允许您创建自己的 自定义维度 并根据需要定义它们。
对于 IOWA,我们创建了一个名为Service Worker 状态的自定义维度,并将其范围设置为 命中(即每次互动)。4 您在 Google Analytics 中创建的每个自定义维度都会在该属性中获得一个唯一的索引,并且在您的跟踪代码中,您可以通过其索引引用该维度。例如,如果我们刚刚创建的维度的索引为 1,我们可以更新我们的逻辑如下,以发送 firstpaint
事件以包含 service worker 状态
ga('send', 'event', {
eventCategory: 'Performance',
eventAction: 'firstpaint',
// Rounds to the nearest millisecond since
// event values in Google Analytics must be integers.
eventValue: Math.round(timeToFirstPaint)
// Sends this as a non-interaction event,
// so it doesn't affect bounce rate.
nonInteraction: true,
// Sets the current service worker status as the value of
// `dimension1` for this event.
dimension1: getServiceWorkerStatus()
});
这可行,但这只会将 service worker 的状态与此特定事件关联起来。由于 Service Worker 状态 对于任何互动都可能有用,因此最好将其包含在发送到 Google Analytics 的所有数据中。
为了将此信息包含在所有命中中(例如,所有页面浏览量、事件等),我们在将任何数据发送到 Google Analytics 之前,在 设置 了 跟踪器 对象本身的自定义维度值。
ga('set', 'dimension1', getServiceWorkerStatus());
一旦设置,此值将与当前页面加载的所有后续命中一起发送。如果用户稍后再次加载页面,则 getServiceWorkerStatus()
函数可能会返回一个新值,并且该值将设置在跟踪器对象上。
关于代码清晰度和可读性的简要说明:由于查看此代码的其他人可能不知道 dimension1
指的是什么,因此最好始终创建一个变量,将有意义的维度名称映射到 analytics.js 将使用的值。
// Creates a map between custom dimension names and their index.
// This is particularly useful if you define lots of custom dimensions.
var customDimensions = {
SERVICE_WORKER_STATUS: 'dimension1'
};
// Creates the tracker object.
ga('create', 'UA-XXXXX-Y', 'auto');
// Sets the service worker status on the tracker,
// so its value is included in all future hits.
ga('set', customDimensions.SERVICE_WORKER_STATUS, getServiceWorkerStatus());
// Postpones sending any hits until after the page has fully loaded.
// This prevents analytics requests from delaying the loading of the page.
window.addEventListener('load', function() {
// Sends a pageview for the initial pageload.
ga('send', 'pageview');
// Sends an event with the time to first paint data.
sendTimeToFirstPaint();
});
正如我所提到的,将 Service Worker 状态 维度与每次命中一起发送,使我们可以在报告任何指标时使用它。
正如您所看到的,IOWA 的所有页面浏览量中几乎有 85% 来自 支持 service worker 的浏览器。
结果:回答我们的问题
一旦我们开始收集数据以回答我们的问题,我们就可以报告该数据以查看结果。(注意:此处显示的所有 Google Analytics 数据代表 2016 年 5 月 16 日至 22 日期间 IOWA 网站的实际 Web 流量)。
我们提出的第一个问题是:Service worker 缓存是否比所有浏览器中现有的 HTTP 缓存机制更有效?
为了回答这个问题,我们创建了一个 自定义报告,其中查看了跨各种维度的 平均页面加载时间 指标。此指标非常适合回答这个问题,因为 load
事件仅在下载完所有初始资源后才会触发。因此,它直接反映了站点所有关键资源的总加载时间。5
我们选择的维度是
- 我们的自定义Service Worker 状态维度。
- 用户类型,指示这是否是用户首次访问该网站,或者他们是否是回访用户。(注意:新访用户将没有缓存任何资源;回访用户可能有。)
- 设备类别,使我们可以比较移动设备和桌面设备的结果。
为了控制非 service worker 相关因素可能会歪曲我们的加载时间结果的可能性,我们将查询限制为仅包括支持 service worker 的浏览器。
正如您所看到的,当受 service worker 控制时,我们应用程序的访问加载速度比非控制访问快得多,即使是那些可能已缓存页面大部分资源的回访用户的访问也是如此。同样有趣的是,平均而言,移动设备上使用 service worker 的访问者的加载速度比新桌面访问者更快。
“……当受 service worker 控制时,我们应用程序的访问加载速度比非控制访问快得多……”
您可以在以下两个表格中查看更多详细信息
平均页面加载时间(桌面设备) | |||
---|---|---|---|
Service Worker 状态 | 用户类型 | 平均页面加载时间(毫秒) | 样本量 |
受控 | 回访用户 | 2568 | 30860 |
支持 | 回访用户 | 3612 | 1289 |
支持 | 新访用户 | 4664 | 21991 |
平均页面加载时间(移动设备) | |||
---|---|---|---|
Service Worker 状态 | 用户类型 | 平均页面加载时间(毫秒) | 样本量 |
受控 | 回访用户 | 3760 | 8162 |
支持 | 回访用户 | 4843 | 676 |
支持 | 新访用户 | 6158 | 5779 |
您可能想知道,对于浏览器支持 service worker 的回访用户来说,如何可能处于非控制状态。对此有几种可能的解释
- 用户在 service worker 有机会完成初始化之前离开了初始访问页面。
- 用户通过开发者工具卸载了 service worker。
这两种情况都相对罕见。我们可以通过查看第四列中的 页面加载样本 值在数据中看到这一点。请注意,中间行的样本量比其他两行小得多。
我们的第二个问题是:Service worker 如何影响网站加载的体验?
为了回答这个问题,我们为 平均事件值 指标创建了另一个自定义报告,并将结果过滤为仅包含我们的 firstpaint
事件。我们使用了设备类别维度和我们的自定义Service Worker 状态维度。
与我原本预期的相反,移动设备上的 service worker 对首次绘制时间的影响远小于对整体页面加载的影响。
“……移动设备上的 service worker 对首次绘制时间的影响远小于对整体页面加载的影响。”
为了探究这是什么原因,我们必须深入挖掘数据。平均值对于总体概述和大致轮廓可能很有用,但要真正了解这些数字在用户范围内的分布情况,我们需要查看 firstpaint
时间的分布。
在 Google Analytics 中获取指标的分布
为了获得 firstpaint
时间的分布,我们需要访问每个事件的各个结果。不幸的是,Google Analytics 并没有让这件事变得容易。
Google Analytics 允许我们按我们想要的任何维度细分报告,但不允许我们按指标细分报告。这并不是说不可能,只是意味着我们必须进一步自定义我们的实现才能获得想要的结果。
由于报告结果只能按维度细分,因此我们必须将指标值(在本例中为 firstpaint
时间)设置为事件的自定义维度。为此,我们创建了另一个名为指标值的自定义维度,并更新了我们的 firstpaint
跟踪逻辑,如下所示
var customDimensions = {
SERVICE_WORKER_STATUS: 'dimension1',
<strong>METRIC_VALUE: 'dimension2'</strong>
};
// ...
function sendTimeToFirstPaint() {
var timeToFirstPaint = getTimeToFirstPaintIfSupported();
if (timeToFirstPaint) {
var fields = {
eventCategory: 'Performance',
eventAction: 'firstpaint',
// Rounds to the nearest millisecond since
// event values in Google Analytics must be integers.
eventValue: Math.round(timeToFirstPaint)
// Sends this as a non-interaction event,
// so it doesn't affect bounce rate.
nonInteraction: true
}
<strong>// Sets the event value as a dimension to allow for breaking down the
// results by individual metric values at reporting time.
fields[customDimensions.METRIC_VALUE] = String(fields.eventValue);</strong>
ga('send', 'event', fields);
}
}
Google Analytics Web 界面目前没有提供可视化任意指标值分布的方法,但在 Google Analytics Core Reporting API 和 Google Charts 库 的帮助下,我们可以查询原始结果,然后自己构建直方图。
例如,以下 API 请求配置用于获取在非受控 service worker 的桌面设备上 firstpaint
值的分布。
{
dateRanges: [{startDate: '2016-05-16', endDate: '2016-05-22'}],
metrics: [{expression: 'ga:totalEvents'}],
dimensions: [{name: 'ga:dimension2'}],
dimensionFilterClauses: [
{
operator: 'AND',
filters: [
{
dimensionName: 'ga:eventAction',
operator: 'EXACT',
expressions: ['firstpaint']
},
{
dimensionName: 'ga:dimension1',
operator: 'EXACT',
expressions: ['supported']
},
{
dimensionName: 'ga:deviceCategory',
operator: 'EXACT',
expressions: ['desktop']
}
],
}
],
orderBys: [
{
fieldName: 'ga:dimension2',
orderType: 'DIMENSION_AS_INTEGER'
}
]
}
此 API 请求返回一个值数组,如下所示(注意:这些只是前五个结果)。结果按从小到大的顺序排序,因此这些行代表最快的时间。
API 响应结果(前五行) | |
---|---|
ga:dimension2 | ga:totalEvents |
4 | 3 |
5 | 2 |
6 | 10 |
7 | 8 |
8 | 10 |
以下是这些结果的通俗解释
- 在 3 个事件中,
firstpaint
值为 4 毫秒 - 在 2 个事件中,
firstpaint
值为 5 毫秒 - 在 10 个事件中,
firstpaint
值为 6 毫秒 - 在 8 个事件中,
firstpaint
值为 7 毫秒 - 在 10 个事件中,
firstpaint
value
值为 8 毫秒 - 等等。
从这些结果中,我们可以推断出每个事件的 firstpaint
值,并创建分布的直方图。我们为运行的每个查询都执行了此操作。
以下是在非受控(但受支持)service worker 的桌面设备上的分布情况

上述分布的 firstpaint
时间中位数为 912 毫秒。
此曲线的形状非常典型,符合加载时间分布。将其与下面的直方图进行对比,该直方图显示了 service worker 正在控制页面的访问中首次绘制事件的分布。

请注意,当 service worker 正在控制页面时,许多访问者体验到接近即时的首次绘制,中位数为 583 毫秒。
“……当 service worker 正在控制页面时,许多访问者体验到接近即时的首次绘制……”
为了更好地了解这两个分布之间的比较情况,下一个图表显示了这两个分布的合并视图。显示非受控 service worker 访问的直方图覆盖在显示受控访问的直方图之上,而这两个直方图都覆盖在显示两者组合的直方图之上。

我发现这些结果有趣的一点是,在初始峰值之后,受控 service worker 的分布仍然具有钟形曲线。我原本期望出现一个大的初始峰值,然后逐渐拖尾,但我没想到曲线中会出现第二个峰值。
当我研究可能导致这种情况的原因时,我了解到,即使 service worker 可以控制页面,它的线程也可能处于非活动状态。浏览器这样做是为了节省资源 - 显然,您不需要您曾经访问过的每个网站的每个 service worker 都处于活动状态并随时待命。这解释了分布的尾部。对于某些用户,启动 service worker 线程时存在延迟。
但是,正如您从分布中看到的那样,即使存在这种初始延迟,具有 service worker 的浏览器提供的内容也比通过网络的浏览器更快。
以下是移动设备上的情况

虽然我们仍然看到接近即时的首次绘制时间显着增加,但尾部却大得多也长得多。这可能是因为,在移动设备上,启动空闲 service worker 线程比在桌面设备上花费的时间更长。这也解释了为什么平均 firstpaint
时间的差异没有我预期的那么大(如上所述)。
“……在移动设备上,启动空闲 service worker 线程比在桌面设备上花费的时间更长。”
以下是按 service worker 状态分组的移动设备和桌面设备上的首次绘制时间中位数的细分
首次绘制时间中位数(毫秒) | ||
---|---|---|
Service Worker 状态 | 桌面设备 | 移动设备 |
受控 | 583 | 1634 |
支持(非受控) | 912 | 1933 |
虽然构建这些分布可视化比在 Google Analytics 中创建自定义报告花费更多时间和精力,但它们比仅使用平均值更能让我们更好地了解 service worker 如何影响我们网站的性能。
Service Worker 的其他影响
除了性能影响外,service worker 还在其他几个方面影响用户体验,这些方面可以使用 Google Analytics 进行衡量。
离线访问
Service worker 允许用户在离线时与您的网站互动,虽然某种形式的离线支持对于任何渐进式 Web 应用程序来说可能至关重要,但在您的情况下,确定其重要性很大程度上取决于离线时发生的使用量。但是我们如何衡量呢?
向 Google Analytics 发送数据需要互联网连接,但不需要在互动发生的准确时间发送数据。Google Analytics 支持事后发送互动数据,方法是指定时间偏移量(通过 qt
参数)。
在过去的两年中,IOWA 一直在使用一个 service worker 脚本,该脚本检测用户离线时发送给 Google Analytics 的失败命中,并在稍后使用 qt
参数重放它们。
为了跟踪用户是在线还是离线,我们创建了一个名为在线的自定义维度,并将其值设置为 navigator.onLine
,然后我们监听 online
和 offline
事件,并相应地更新维度。
为了了解用户在使用 IOWA 时离线的普遍程度,我们创建了一个细分,目标是至少有一次离线互动的用户。结果表明,这几乎占到 5% 的用户。
推送通知
Service worker 允许用户选择接收推送通知。在 IOWA 中,当用户日程表中的会议即将开始时,他们会收到通知。
与任何形式的通知一样,重要的是找到在为用户提供价值和打扰用户之间取得平衡。为了更好地了解哪种情况正在发生,重要的是跟踪用户是否选择接收这些通知,他们在收到通知时是否与之互动,以及之前选择接收通知的用户是否有改变偏好并选择退出。
在 IOWA 中,我们只发送与用户个性化日程相关的通知,这是只有登录用户才能创建的内容。这限制了可以接收通知的用户群体为已登录用户(通过名为Signed In的自定义维度跟踪)且其浏览器支持推送通知的用户(通过另一个名为Notification Permission的自定义维度跟踪)。
以下报告基于用户指标和我们的 Notification Permission 自定义维度,并按在某个时间点登录且浏览器支持推送通知的用户进行细分。
很高兴看到超过一半的已登录用户选择接收推送通知。
应用安装横幅
如果渐进式 Web 应用符合标准并且用户经常使用,则可能会向该用户显示应用安装横幅,提示他们将应用添加到主屏幕。
在 IOWA 中,我们使用以下代码跟踪了向用户显示这些提示的频率(以及是否被接受)
window.addEventListener('beforeinstallprompt', function(event) {
// Tracks that the user saw a prompt.
ga('send', 'event', {
eventCategory: 'installprompt',
eventAction: 'fired'
});
event.userChoice.then(function(choiceResult) {
// Tracks the users choice.
ga('send', 'event', {
eventCategory: 'installprompt',
// `choiceResult.outcome` will be 'accepted' or 'dismissed'.
eventAction: choiceResult.outcome,
// `choiceResult.platform` will be 'web' or 'android' if the prompt was
// accepted, or '' if the prompt was dismissed.
eventLabel: choiceResult.platform
});
});
});
在看到应用安装横幅的用户中,约有 10% 的用户选择将其添加到主屏幕。
可能的跟踪改进(下次)
今年我们从 IOWA 收集的分析数据非常宝贵。但事后来看,总能发现漏洞和改进下次工作的机会。在完成今年的分析后,以下是我希望我们能以不同方式做的两件事,希望读者在考虑实施类似策略时可以参考。
1. 跟踪更多与加载体验相关的事件
我们跟踪了几个与技术指标相对应的事件(例如 HTMLImportsLoaded、WebComponentsReady 等),但由于大部分加载是异步完成的,因此这些事件触发的点不一定与整体加载体验中的特定时刻相对应。
我们没有跟踪(但希望跟踪)的主要加载相关事件是启动画面消失且用户可以看到页面内容的时间点。
2. 将分析客户端 ID 存储在 IndexedDB 中
默认情况下,analytics.js 将客户端 ID 字段存储在浏览器的 Cookie 中;遗憾的是,service worker 脚本无法访问 Cookie。
当我们尝试实施通知跟踪时,这给我们带来了问题。我们希望在每次向用户发送通知时,都从 service worker(通过Measurement Protocol)发送一个事件,然后在用户点击通知并返回应用时,跟踪该通知的重新互动成功率。
虽然我们能够通过 utm_source
campaign parameter 跟踪通知的总体成功率,但我们无法将特定的重新互动会话与特定用户关联起来。
为了解决这个限制,我们可以做的是通过 IndexedDB 在我们的跟踪代码中存储客户端 ID,然后 service worker 脚本就可以访问该值。
3. 让 service worker 报告在线/离线状态
检查 navigator.onLine
可以让您知道您的浏览器是否能够连接到路由器或局域网,但这不一定能告诉您用户是否真正连接到互联网。而且由于我们的离线分析 service worker 脚本只是重放失败的命中(没有修改它们或将它们标记为失败),我们可能低估了我们的离线使用情况。
未来,我们应该跟踪 navigator.onLine
的状态,以及命中是否因初始网络故障而由 service worker 重放。这将使我们更准确地了解真实的离线使用情况。
总结
本案例研究表明,使用 service worker 确实提高了 Google I/O Web 应用在各种浏览器、网络和设备上的加载性能。它还表明,当您查看各种浏览器、网络和设备上的加载数据分布时,您可以更深入地了解这项技术如何处理真实场景,并发现您可能没有预料到的性能特征。
以下是 IOWA 研究的一些主要结论
- 平均而言,当 service worker 控制页面时,新访客和回访访客的页面加载速度都比没有 service worker 时快得多。
- 对于许多用户来说,访问由 service worker 控制的页面几乎是瞬间加载完成的。
- Service worker 在不活动时,启动需要一些时间。但是,不活动的 service worker 仍然比没有 service worker 的性能更好。
- 不活动的 service worker 在移动设备上的启动时间比在桌面设备上更长。
虽然在一个特定应用程序中观察到的性能提升通常对向更广泛的开发者社区报告很有用,但重要的是要记住,这些结果特定于 IOWA 网站的类型(活动网站)和 IOWA 的受众类型(主要是开发者)。
如果您正在您的应用程序中实施 service worker,那么重要的是您要实施自己的衡量策略,以便您可以评估自己的性能并防止未来出现倒退。如果您这样做了,请分享您的结果,以便每个人都能受益!
脚注
- 将我们的 service worker 缓存实现的性能与我们仅使用 HTTP 缓存的网站性能进行比较,这并不完全公平。因为我们正在为 service worker 优化 IOWA,所以我们没有花太多时间为 HTTP 缓存进行优化。如果我们这样做了,结果可能会有所不同。要了解有关优化网站以使用 HTTP 缓存的更多信息,请阅读优化内容效率。
- 根据您的网站加载其样式和内容的方式,浏览器有可能在内容或样式可用之前就能够绘制。在这种情况下,
firstpaint
可能对应于空白的白色屏幕。如果您使用firstpaint
,请务必确保它对应于您网站资源加载过程中的一个有意义的点。 - 从技术上讲,我们可以发送一个 timing 命中(默认情况下是非互动的)来捕获此信息,而不是事件。实际上,timing 命中被添加到 Google Analytics 中专门用于跟踪此类加载指标;但是,timing 命中在处理时会被大量抽样,并且它们的值不能在细分中使用。鉴于当前的这些限制,非互动事件仍然更适合。
- 为了更好地理解在 Google Analytics 中为自定义维度赋予什么作用域,请参阅 Analytics 帮助中心的自定义维度部分。 了解 Google Analytics 数据模型也很重要,该模型由用户、会话和互动(命中)组成。要了解更多信息,请观看 Analytics Academy 关于 Google Analytics 数据模型的课程。
- 这不包括在加载事件之后延迟加载的资源。