本文主要是对 CovalenceConf 2019: Visual Studio Code – The First Second 这次分享的介绍,CovalenceConf 是一个以 Electron 构建桌面软件为主题的技术会议,这也是 VS Code 团队为数不多的对外分享之一(质量较高),主要分享了 VS Code 是如何优化启动性能的。
VS Code 是少有的核心功能完全使用 Web 技术构建的桌面编辑器,在这之前是 Atom,但师出同门(Electron) 的 Atom 最为人诟病的就是其性能问题。VS Code 自诞生那天起,保证性能优先就是最重要的一条准则,诚然相比老牌的 Sublime Text,VS Code 性能表现并不能称得上优秀,但相比之下已经完全是可以接受的水平了。
社区也有很多开源编辑器采用了前后端分离技术,也就是使用 Web 技术构建编辑器 UI 部分,而核心的 TextBuffer 都使用 Native 实现,这类编辑器甚至可以替换 UI 层的技术实现,例如使用我们常见的 Electron,又或是 QT 等桌面端技术,因为编辑器涉及面太广,这里暂时不再赘述。
最开始我是抱着来找黑魔法的想法来看这次分享的,然而当我结合代码看了三遍分享后满屏都是四个字:没有银弹。
总结下来就是几个点 * 按照优先级划分启动顺序,永远确保文件树和编辑器最快渲染出来,并且光标第一时间在编辑器内跳动(这意味着用户可以开始编辑文件了) * 测量监控性能数据,每个版本都收集尽可能多的数据来直观的表现性能 * 对于出现的性能瓶颈快速做出改进。
性能优化是一个长期的过程,并不是某个时间段集中精力优化一波就高枕无忧了,你可以在 VS Code 的 issue 列表里找到一系列标签为 perf 和 startup-perf 相关的 issue,并且这些 issue 都有人长期跟踪解决的。
在这之前我们需要明确几个首屏启动性能相关的概念,这里列举的并不是全部,有兴趣的可以自行在 Web.Dev 查找其他指标。
| 缩写 | 英文全称 | 说明 | | -- | ----- | ------ | | FCP | First Contentful Paint| 浏览器渲染DOM内容的第一个字节 | | LCP | Largest Contentful Paint | 可是区内最大块的文本或图像渲染时间 | | FID | First Input Delay | 用户实现交互操作的相应时间,例如点击事件有反应 | | FCI | First CPU Idle| 首次CPU空闲时间 | | TTI | Time to Interactive | 页面开始加载到稳定可交互的时间,所有按钮点击都有反应 |
我们不一定关注以上所有的指标,但有几个对用户体感差异较为明显的指标可以重点关注一下,例如 LCP 、 FID 以及 TTI。
还有另一项指标 FMP (First Meaningful Paint 首次有效渲染时间) 不是很推荐,因为它无法直观的识别页面的主体内容是否加载完成,例如某些网站会在有意义的内容渲染前展示一个全屏的 Loading 动画,这对用户来讲显然是没有任何意义的,而相比之下 LCP 更为纯粹,它只看页面主体内容、图像是否加载完成。
这与 VS Code 的原则不谋而合,对于文本编辑器来说,性能好坏最直接的问题就是从点开图标到我可以输入文本需要多久?VS Code 的答案是 1 秒 (热启动在 500 毫秒左右)。
所以第一步永远是测量,不管是 console.time 还是新的 Performance API,在关键的节点添加这些性能标记,通过大量的数据收集可以得到一个真实的性能指标。VS Code 选择了 Performance API ,这样更方便汇总上报数据。运行 Startup Performance 命令可以看到这些性能指标的耗时 (总耗时2s+, 实际上 TTI 是 977ms)。
数据收集除了能看到当前真实的性能指标,更能帮助我们发现耗时花在了哪些地方。要做到这一点,需要找到这些关键节点。VS Code 是基于 Electron ,除了常规的页面渲染之外,还有一包括等待 Electron App Ready、创建窗口、LoadURL 等耗时,这部分的性能有专业的团队来保障(Electron、V8),不需要关心太多。所以重点需要关心的是 UI 部分的呈现及可交互时间。
回到我们擅长的前端领域,当我们谈到性能优化时,总是逃不开几条金科玉律:
所有这些优化的目的,都是为了尽可能快的加载并执行 JavaScript 代码。在 SPA 大行其道的今天,JavaScript 加载越慢,就意味着用户看到的白屏时间更久(于是又催生出了 SSR 这种方案)。
V8 Code Cache 的目的是减少对 JavaScript 代码的解析与编译开销,我们知道 V8 使用 JIT (Just in time compilation) 来执行 JavaScript 代码,也就是说在 JS 脚本执行之前,必须对其进行解析和编译,这一步的开销是较大的。而 Code Cache 技术是在首次编译时将结果缓存下来,下一次加载相同的脚本时直接读取磁盘上的缓存来执行,省去了解析、编译的过程,从而使脚本执行更快。V8 提供了开放的 API,因此,任何使用 V8 的软件都可以调用该 API,同时 Node.js 5.7.0 版本起 vm 模块也提供了对该 API 的包装。由于 VS Code 使用 AMD Loader 作为模块加载器,所以内置实现了 V8 Code Cache。
不过对于大多数应用来说,没必要自己实现一遍缓存逻辑,直接使用 v8-compile-cache ,在入口处引入 v8-compile-cache 即可。
import 'v8-compile-cache';
经过一系列的优化,VS Code 的 JS Bundle 加载速度从一开始的接近 1.5 秒优化到了 0.5 秒。
编辑器的启动包含许多逻辑,例如快捷键、编辑器、文件浏览器、调试器等功能的初始化与事件绑定等等,每个看起来都是非常重要的核心功能,而当软件体积不断增大时,这些逻辑可能会像高速公路上的车辆一样,如果毫无秩序,每一辆车都想以最快的速度通过,反而会导致所有车辆停滞不前,造成拥堵。
拆分生命周期的一个重要目的就是将这些核心功能的优先级进行排序,黄金原则就是尽可能快的让用户最关心的界面先渲染出来。对于 VS Code 来说,就是文件资源管理器和编辑器。VS Code 的核心功能都是通过 Contribution 来注册的。在早期的版本中,这些贡献点会在启动时就全部一起进行注册,这直接导致编辑器的加载被阻塞,最直观的表现就是界面所有 UI 都已经渲染出来并且可操作时,编辑器内的文本还没有加载出来(它们可能很大)。
拆分生命周期阶段本质上就是将这些贡献点分阶段来实例化,具体来说,VS Code 将整个启动的生命周期分为了四个阶段
生命周期执行的核心代码 ```typescript // src/vs/workbench/common/contributions.ts
start(accessor: ServicesAccessor): void { const instantiationService = this.instantiationService = accessor.get(IInstantiationService); const lifecycleService = this.lifecycleService = accessor.get(ILifecycleService);
[LifecyclePhase.Starting, LifecyclePhase.Ready, LifecyclePhase.Restored, LifecyclePhase.Eventually].forEach(phase => { this.instantiateByPhase(instantiationService, lifecycleService, phase); }); }
instantiateByPhase(instantiationService: IInstantiationService, lifecycleService: ILifecycleService, phase: LifecyclePhase): void { // 当达到对应的阶段时直接实例化贡献点 if (lifecycleService.phase >= phase) { this.doInstantiateByPhase(instantiationService, phase); }
// 未达到对应阶段时一直等待 else { lifecycleService.when(phase).then(() => this.doInstantiateByPhase(instantiationService, phase)); } } ```
正如分享的作者 Johannes Rieken 所说,这并不是非常复杂的技术问题,而是以一种更聪明的方式来对启动过程重新排序。这样一来,整体的启动过程会更加的有序,对于一些不是那么重要的任务,将它们的优先级靠后一些,从而确保能在第一时间将编辑器呈现出来,使用户进入可以编辑的状态。
// busy busy busy busy
// busy busy busy busy
// busy busy busy busy
requestIdleCallback((dealline) => {
// idle idle idle idle
// idle idle idle idle
// idle idle idle idle
})
// busy busy busy busy
// busy busy busy busy
// busy busy busy busy
requestIdleCallback 是一个浏览器提供的 API,用于在 CPU 空闲时间执行一些任务。相比 setTimeout,requestIdleCallback 的执行时机由浏览器来控制,因为浏览器知道何时才是空闲时间。利用 requestIdleCallback,可以将一些必要但不紧急的工作延后处理,例如常见的一些埋点上报逻辑,可能会在触发某些高频率的交互操作时执行,而如果将这些逻辑与事件处理放在一起,很容易影响操作体验。
requestIdleCallback 可以传入第二个参数,表示超时时间。表示最晚多久以后来执行回调函数。typescript requestIdleCallback(processPendingAnalyticsEvents, { timeout: 2000 }); `
一般来说应该将执行时机交还给浏览器,让浏览器自行决定何时调用回调,如果设置了超时时间,则可能因为执行顺序被打乱。
对于一些耗时的确会很长的操作,例如打开一个巨大的文件,显然即便是性能最好的的优化手段,也无法将这种耗时降到毫秒级。但我们可以通过一些小的手段让这种交互 感觉更快。例如在这个 Case 中,点击打开一个大文件(2.5m)时,先将编辑器 Tab 以及面包屑渲染出来。
除此之外,对于切换编辑器 Tab 时,使用 MouseDown 而非 MouseUp 事件,一次点击事件从触发 MouseDown 到 MouseUp 中间的耗时平均是50ms,这意味着在切换编辑器时,鼠标点击至少 50ms 后包括 Tab 以及面包屑才会有反应。我们可以写一个很简单的 Demo 来观察这两者的区别。
例如这张截图中,点击 package.json 时,文件内容还是另一个文件,而面包屑已经变成了 package.json。使用这种小技巧,在 VS Code 中切换编辑器时,会令用户觉得「反应好快」,
不建议在所有点击事件触发的地方都使用 MouseDown 来代替 MouseUp,因为复杂的 UI 可能还需要处理如拖动等事件,这会让事件处理更加复杂。
这篇分享的内容没有太多看起来非常硬核的技术手段,更多的是对当前性能瓶颈的测量,以及更聪明的「重新排列组合」,或者说采用了一系列使体验更好的策略,这对用户体验的提升是巨大的。
本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/48_J7xNwOPRX6rvgWjyolA
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。