写点什么

Slack 的 Service Worker 实践:更快的启动速度与离线支持

  • 2019-10-17
  • 本文字数:3457 字

    阅读完需:约 11 分钟

Slack的Service Worker实践:更快的启动速度与离线支持

Service Worker 是网络请求的强大代理,它允许开发人员用少量 JavaScript 控制浏览器响应各个 HTTP 请求。本文将主要讲述 Slack 的 Service Worker 实践,以实现更快的启动速度与离线支持。


我们最近更新了 Slack 的桌面版,新版最大的改进一就是启动速度更快了。在本文中,我们将回顾一下提升 Slack 运行速度,从而改善用户体验的探索工作。


改进方案是从一个名为“快速启动”的原型开始的,该原型旨在(你猜对了)尽快启动 Slack。我们使用了 CDN 缓存的 HTML 文件、持久化的 Redux 存储和一个服务 Worker,从而在不到一秒钟的时间内启动客户端的精简版本(当时,使用 1-2 个工作区的用户普遍需要大约 5 秒钟的启动时间)。Service Worker 是速度提升的最大功臣,它还带来了用户亟需的脱机运行 Slack 的能力。这个原型让我们看到了桌面客户端架构彻底重构后的潜力。基于这种潜力,我们开始基于提升启动速度并引入脱机支持的核心期望重建 Slack 客户端。下面就来深入谈谈背后的工作机制。

什么是 Service Worker?

Service Worker 是网络请求的强大代理,它使开发人员可以用少量 JavaScript 控制浏览器响应各个 HTTP 请求。它们带有丰富而灵活的缓存 API,设计为将请求对象用作键,将响应对象用作值。像 Web Worker 一样,它们独立于单独运行的窗口,在自己的进程中运行。


Service Worker 是现已弃用的应用程序缓存功能的后续工具,后者是为网站提供离线功能的 API。AppCache 的工作机制是提供你要缓存下来供离线使用的静态文件清单……就是这样。它简单但不灵活,无法为开发人员提供控制权。当 W3C 编写 Service Worker 规范时非常重视之前的这些反馈,最后,Service Worker 对你的应用程序或网站进行的所有网络交互都提供了细微的控制权。


当我们第一次涉足这项技术时,支持它的浏览器只有 Chrome 而已,但是我们知道它很快就会广泛普及。现在,所有主要浏览器都开始支持 Service Worker 了。

我们如何使用 Service Worker

当你首次启动新版本的 Slack 时,我们将获取全套资产(HTML、JavaScript、CSS、字体和声音)并将其放置在 Service Worker 的缓存中。我们还将获取你的内存 Redux 存储的副本,并将其推送到 IndexedDB。下次启动时,我们检测这些缓存是否存在。如果存在,我们将使用它们来启动应用程序;如果你在线,我们将在引导后获取新数据。如果不存在,你的客户端也还是可用的。


为了区分这两种路径,我们给它们分别命名为:暖启动和冷启动。通常用户第一次启动是冷启动,没有缓存资产,也没有持久数据。暖启动时我们启动 Slack 所需要的全部数据都存储在用户本地计算机上。请注意,大多数二进制资产(图像、PDF 和视频等)均由浏览器缓存处理(并由普通的缓存头控制)。他们不需要 Service Worker 的显式处理即可离线加载。


Service Worker 生命周期

Service Worker 可以处理三个事件:安装获取激活。每个事件我们都会深入研究,但首先必须下载并注册 Service Worker。生命周期取决于浏览器处理 Service Worker 文件更新的方式。根据 MDN 的 API 文档:


当下载的文件是新文件时尝试安装——所谓新文件既可能是与现有 Service Worker 不同(按字节比较),或者是此页面 / 站点遇到的第一个 Service Worker。


每次我们更新相关的 JavaScript、CSS 或 HTML 文件时,它都会通过自定义的 webpack 插件运行,该插件会生成这些文件的带有唯一哈希值的清单。它被嵌入到 Service Worker 中,即使实现本身未更改也将在下次启动时触发更新。

安装

每当 Service Worker 更新时我们都会收到安装事件。作为响应,我们遍历嵌入式清单中的文件,获取每个文件并将它们放入共享的缓存桶中。文件使用新的缓存 API 存储,这个 API 是 Service Worker 规范的另一部分。它存储以以请求对象为键的响应对象:非常优雅直观,且与 Service Worker 事件接收请求并返回响应的方式完全一致。


我们通过部署时间为缓存桶设置键。时间戳嵌入在我们的 HTML 中,因此可以作为文件名的一部分传递给所有资产请求。分别缓存各个部署中的资产是很重要的,可以预防不匹配现象。通过这种设置,我们可以确保最初获取的 HTML 文件从缓存或网络中只能获取兼容的资产。

获取

注册后,我们的 Service Worker 将被设置为处理来自同一来源的每个网络请求。你无法选择是否让 Service Worker 处理请求,但是你完全可以控制该请求的处理方式。


首先我们检查请求。如果它在清单中并且存在于缓存中,我们将返回已缓存的响应。如果没在清单里,我们将为相同的请求返回一个获取调用,将请求传递到网络,好像不存在 Service Worker 一样。以下是我们获取处理程序的简化版本:


self.addEventListener('fetch', (e) => {  if (assetManifest.includes(e.request.url) {    e.respondWith(      caches        .open(cacheKey)        .then(cache => cache.match(e.request))        .then(response => {          if (response) return response;          return fetch(e.request);        });    );  } else {    e.respondWith(fetch(e.request));  }});
复制代码


在实际的实现中有更多 Slack 特定的逻辑,但获取处理程序的核心就是这么简单。



从 Service Worker 返回的响应将在网络检查器的大小列中标记为“(ServiceWorker)”

激活

成功安装新的 Service Worker 或更新 Service Worker 后,会触发 activate 事件。我们用它来回顾缓存资产,并让所有超过 7 天的缓存桶失效。它不仅能打扫好房间,也可以防止客户端使用过时的资产启动。

落后一个版本

你可能已经注意到,我们的实现意味着在第一次启动 Slack 客户端后,所有人都将收到上次注册 Service Worker 时获取的资产,而不是启动时最新部署的资产。我们的初始实现尝试在每次引导后更新 Service Worker。但是,典型的 Slack 客户可能只在每天早晨启动一次,并且可能会发现自己整整一天都在用落后一个版本的应用(我们每天更新多次代码)。


与你快速浏览的典型网站不一样的是,Slack 在人们工作时会在他们的计算机上停留数小时之久。这使我们的代码具有较长的保存期限,并且需要一些不一样的方法来保持最新状态。


我们仍然希望用户使用最新的版本,以便获得最新的错误修复、性能改进和功能。发布新版客户端后不久,我们就在抖动的间隔中添加了注册过程以缩小间隔。如果自上次更新以来有新版本部署,我们将获取新资产以备下次启动。如果没有,注册机制什么都不会做。做出这项更改后,客户端启动资产的平均过时时间减少了一半。



定期获取新版本,但仅使用最新版本启动

功能标记同步

功能标记是我们代码库中的条件,可让我们合并未完成的工作以准备公开发布。有了它,我们在完成功能之前很长时间就可以与应用程序的剩余部分一起自由测试功能,从而降低了风险。


Slack 的日常工作流程是发布新功能以及我们 API 中的相应更改。在引入 Service Worker 之前我们已经保证两者是同步的,但现在我们的缓存资产落后了一个版本,客户端很可能就和后端不同步了。为了解决这个问题,我们不仅要缓存 资产,还会缓存 一些 API 响应。


Service Worker 处理每个网络请求的能力简化了解决方案。每次 Service Worker 更新时,我们也会发出 API 请求,并将响应缓存在与资产相同的存储桶中。这会将我们的功能和实验与正确的资产相关联——可能它们都过时了,但一定要保持同步。


这是 Service Worker 可能引发问题的冰山一角。这个问题用 AppCache 要么完全没法解决,要么需要非常复杂的技术栈;但是有了 Service Worker 和缓存 API,解决方案就变得非常简单且顺其自然了。

总结

Service Worker 将 Slack 的资产存储在本地以备下次启动时使用,从而加快了启动速度。我们最大的延迟和可变性来源就是网络。而且如果你可以将网络排除在外,那么你也很容易提供离线支持。现在我们对脱机功能的支持非常简单——你可以启动 Slack,从以前阅读过的对话中读取消息,并将未读标记设置为在线后再同步——但有了这个舞台,我们将来就能开发更高级的离线功能了。


经过几个月的开发、试验和优化,我们已经学到了很多有关 Service Worker 如何在实践中操作的知识。而且该技术已经得到了大规模应用的实证:在公开发布后不到一个月的时间里,我们就通过数百万已安装的 Service Worker 成功地为每天数千万的请求提供了服务。与传统客户端相比,这意味着启动时间减少了约 50%;与冷启动相比启动时间缩短了约 25%。



在浏览器中使用 p50 旧版、暖启动和冷启动的测试结果(越低越好)


原文链接:


https://slack.engineering/service-workers-at-slack-our-quest-for-faster-boot-times-and-offline-support-3492cf79c88


2019-10-17 10:212010

评论

发布
暂无评论
发现更多内容

简单学习一下 MyBatis 动态SQL使用及原理

做梦都在改BUG

Java mybatis

不服不行!Github爆火的「高并发秒杀顶级教程」,先睹为快

做梦都在改BUG

Java 高并发 秒杀系统

PHP快速使用RabbitMQ实现项目中部分业务的解耦

北桥苏

php RabbitMQ thinkphp

快速地找到任何文件或文件夹:Find Any File Mac版

真大的脸盆

Mac Mac 软件 文件搜索 搜索文件 文件查找工具

windows下docker的安装与镜像的制作提交

北桥苏

Docker Docker 镜像

【源码分析】【seata】at 模式分布式事务-server端与客户端交互

如果晴天

源码分析 分布式事务 分布式锁 seata Seata框架

PCB如何设计防静电?华秋一文告诉你

华秋电子

Avive World算力挖矿系统开发技术

薇電13242772558

算力

PHP高并发高负载下的3种实战场景解决方法

北桥苏

php 高并发优化 thinkphp

跑步课程导入能力,助力科学训练

HarmonyOS SDK

HMS Core

Elasticsearch分布式搜索引擎的基本使用

北桥苏

php elasticsearch

开源轻量级 IM 框架 MobileIMSDK 的Uniapp客户端库已发布

JackJiang

网络编程 即时通讯 即时通讯IM

膜拜!阿里内部都在强推的K8S(kubernetes)学习指南,不能再详细了

做梦都在改BUG

Java Kubernetes k8s

如何使用appuploader制作apple证书​

雪奈椰子

Confluence(知识库软件)和腾讯文档(多人协作文档软件)的区别

爱吃小舅的鱼

Confluence PingCode 文档管理工具

袋鼠云产品功能更新报告05期|应有尽“优”,数栈一大波功能优化升级!

袋鼠云数栈

大数据 hadoop 数据中台

重磅来袭!微服务的里程碑SpringCloudAlibaba

做梦都在改BUG

Java 架构 微服务 Spring Cloud spring cloud alibaba

从 MySQL 到 Oracle 再到全面 TiDB ,云盛海宏的数据库架构实践

TiDB 社区干货传送门

短信验证 创建应用

MobTech袤博科技

OSS云文件列举分页

北桥苏

php OSS 分页 上传 thinkphp

ZeroErr 零误框架

西风逍遥游

耗时一个月,整理了这份大厂Java面试 / 学习指南,共计1500+ 题全面解析

采菊东篱下

Java 程序员

文盘Rust -- rust连接oss

TiDB 社区干货传送门

开发语言

方案精讲丨TiDB 在社交场景的解决方案实践

TiDB 社区干货传送门

小心白蛇!PyPI仓库被持续投放White Snake后门组件

墨菲安全

pypi 开源软件供应链安全

2023年报业网络安全等级保护定级流程

行云管家

网络安全 等级保护 报业

这套Github上40K+star面试笔记,可以帮你搞定95%以上的Java面试

做梦都在改BUG

Java java面试 Java八股文 Java面试题 Java面试八股文

phpstorm开发项目中5种常用的使用方法

北桥苏

php PHPStorm

2023 年最新 Java 面试必背八股文,1338 道最新大厂架构面试题

架构师之道

Java 面试

不到1分钟,帮你剪完旅行vlog,火山引擎全新 AI「神器」真的这么绝?

字节跳动技术范儿

字节跳动 算法 计算机视觉 云服务 火山引擎

并发编程-ReentrantLook底层设计

做梦都在改BUG

Java 并发编程 ReentrantLook

Slack的Service Worker实践:更快的启动速度与离线支持_大前端_Slack Engineering_InfoQ精选文章