对冷启动的执念
冷启动是应用程序向用户做出的第一个承诺。如果应用需要超过一秒才能进入可用状态,那么无论之后运行得多快,我们已经让用户觉得这是一个运行缓慢的应用。
这也是人们最常经历的时刻。打开习惯追踪应用,只需几秒钟就能勾选一项任务;打开偏头痛追踪应用,则是在感觉不适时,为了快速记录症状。对于此类应用而言,启动并非体验的序幕——它本身就是体验的主要部分。.
我们的目标
我们的目标是 小于 600 毫秒 从点击图标到在一部使用了五年的iPhone上显示交互式用户界面。这发生在操作系统加载二进制文件、分配内存并向我们提供主线程之后。从交接完成到第一帧显示期间发生的一切,都由我们负责。
“交互性”是关键所在。那种瞬间弹出后就一直停留在那里的启动画面不算数;第一帧满是占位符、片刻后才自动重新排列的画面也不算数。真正的目标是:当你点击想要的内容时,它能立即做出响应。.
我们之所以在旧设备上进行测量,而不是在新设备上,原因与我们之所以在那里进行测试是一样的:最新款手机几乎能掩盖任何错误。.
它迫使……
一旦达到这个数字,很多争论就会早早平息。在启动路径上无法进行网络连接。第三方 SDK 很难被接受——其中大多数会在……之前启动后台任务 application(_:didFinishLaunching…) 甚至会返回结果。图像缓存采用延迟加载。数据库迁移在后台队列中运行,绝不会阻塞主队列。
由此衍生出一些设计习惯。首屏内容基于设备上已有的数据生成,因此应用会立即显示真实内容,如有需要更新,则会悄无声息地刷新。首屏不需要的功能,只有在用户主动请求时才会启用。 每当我们想添加一个库时,在询问它能为我们做什么之前,我们会先问它启动时会做什么。.
权衡取舍
这种做法并非没有代价。拒绝使用便捷的 SDK,有时意味着我们必须自己编写并维护等效的代码。优先显示本地数据,意味着在设计时要考虑到数据可能略有过时的状况。延迟加载则需要格外小心,以避免在首次打开较重的页面时出现卡顿。 我们愿意承担这些成本,因为否则,每个用户在每次启动应用时都将永远为此付出微小的代价。.
我们的失误
启动时间很少会因一次剧烈的变化而突然恶化。它是逐渐恶化的:这里加了一点初始化代码,那里多了一项检查,单看每一项都无伤大雅。我们就是通过惨痛的教训才明白这一点的——直到很晚才发现,应用程序的启动速度变慢了,却找不到任何一个具体的提交记录来归咎。 现在,每次发布时都会在参考设备上检查启动时间,因此性能漂移在还很小的时候就能被发现。.
这一原则同样适用于我们的其他平台。无论是 Windows 应用还是浏览器扩展程序的弹出窗口,都有其特有的“冷启动”过程,而同样的规则也适用:立即展示有用的内容,其他内容则暂不显示。.
为什么值得
这种自律终将物有所值。一旦启动速度快了,其他一切也会随之加快——因为同样的规则在任何地方都适用。.