自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

關(guān)于 VS Code 優(yōu)化啟動(dòng)性能的實(shí)踐

新聞
本文主要是對(duì)CovalenceConf 2019: Visual Studio Code – The First Second 這次分享的介紹,CovalenceConf 是一個(gè)以 Electron 構(gòu)建桌面軟件為主題的技術(shù)會(huì)議,這也是 VS Code 團(tuán)隊(duì)為數(shù)不多的對(duì)外分享之一。

[[421135]]

本文主要是對(duì)   CovalenceConf 2019: Visual Studio Code – The First Second  這次分享的介紹,CovalenceConf 是一個(gè)以 Electron 構(gòu)建桌面軟件為主題的技術(shù)會(huì)議,這也是 VS Code 團(tuán)隊(duì)為數(shù)不多的對(duì)外分享之一(質(zhì)量較高),主要分享了 VS Code 是如何優(yōu)化啟動(dòng)性能的。

TL ; DR

▐     開(kāi)頭的一些內(nèi)容

  1. VS Code 的指導(dǎo)原則之一是盡可能快的讓用戶可以進(jìn)入編輯狀態(tài)

  2. 啟動(dòng)速度優(yōu)化并不復(fù)雜,但它是許許多多小改進(jìn)的總和,沒(méi)有銀彈

  3. Monaco Editor  最早是 2011 年底開(kāi)始的一個(gè)實(shí)驗(yàn)項(xiàng)目,目的是構(gòu)建一款在瀏覽器中運(yùn)行的開(kāi)發(fā)人員工具

▐     關(guān)于啟動(dòng)性能優(yōu)化

  • 性能優(yōu)化基本的法則

  1. 測(cè)量,測(cè)量,還是測(cè)量,并基于此建立一個(gè)基準(zhǔn)線 (VS Code 使用 Performance API,并對(duì)整個(gè)啟動(dòng)過(guò)程中的關(guān)鍵節(jié)點(diǎn)打點(diǎn))

  2. 建立監(jiān)控,針對(duì)每個(gè)版本的性能變化快速做出優(yōu)化措施

  3. 用一臺(tái)7年前(現(xiàn)在來(lái)說(shuō)是9年前)的 ThinkPad 做測(cè)試,確保它能在1.8秒內(nèi)啟動(dòng) VS Code

  4. 不要過(guò)多的專注于 Electron、V8 這些底層依賴,因?yàn)橛幸蝗郝斆鞯娜嗽诓粩嗟膬?yōu)化它們,專注于加載代碼以及運(yùn)行程序。

  • 確保代碼盡可能快的加載

  1. 使用 Rollup、Webpack 等構(gòu)建工具將代碼打包成單文件,這可以節(jié)省約 400ms

  2. 壓縮代碼,可以節(jié)省約 100ms

  3. 使用 V8 Cached Data 將一些模塊代碼編譯成字節(jié)碼文件(一種中間態(tài)),這可以節(jié)省約 400ms, VS Code 自己使用 AMD Loader 實(shí)現(xiàn)了這個(gè)緩存,也可以直接用  v8-compile-cache  這個(gè)包。

  • 生命周期階段(Lifecycle Phases),分先后順序來(lái)做應(yīng)該做的事?不要一股腦全部執(zhí)行

  1. 梳理清楚所有關(guān)于啟動(dòng)階段事情的優(yōu)先級(jí)

  2. 保證資源管理器和編輯器初始化,然后再做其他不是非常重要的事

  • requestIdleCallback, 將不那么重要的工作放在瀏覽器空閑時(shí)間執(zhí)行

  1. 參考  Idle Until Urgent  這篇文章

  • 通過(guò)一些小技巧使得界面「體感上」較快

  1. 切換編輯器時(shí),使用 MouseDown 來(lái)替代 MouseUp / Click 事件,先確保 Tab 很快的切換

  2. 打開(kāi)耗時(shí)較大的文件時(shí),首先將面包屑、狀態(tài)欄等其他 UI 部分渲染出來(lái),使得用戶感覺(jué) UI 反應(yīng)很快

  • 重復(fù)以上步驟

沒(méi)有銀彈

VS Code 是少有的核心功能完全使用 Web 技術(shù)構(gòu)建的桌面編輯器,在這之前是 Atom,但師出同門(Electron) 的 Atom 最為人詬病的就是其性能問(wèn)題。VS Code 自誕生那天起,保證 性能優(yōu)先 就是最重要的一條準(zhǔn)則,誠(chéng)然相比老牌的 Sublime Text,VS Code 性能表現(xiàn)并不能稱得上優(yōu)秀,但相比之下已經(jīng)完全是可以接受的水平了。

社區(qū)也有很多開(kāi)源編輯器采用了前后端分離技術(shù),也就是使用 Web 技術(shù)構(gòu)建編輯器 UI 部分,而核心的 TextBuffer 都使用 Native 實(shí)現(xiàn),這類編輯器甚至可以替換 UI 層的技術(shù)實(shí)現(xiàn),例如使用我們常見(jiàn)的 Electron,又或是 QT 等桌面端技術(shù),因?yàn)榫庉嬈魃婕懊嫣珡V,這里暫時(shí)不再贅述。

最開(kāi)始我是抱著來(lái)找黑魔法的想法來(lái)看這次分享的,然而當(dāng)我結(jié)合代碼看了三遍分享后滿屏都是四個(gè)字: 沒(méi)有銀彈。

總結(jié)下來(lái)就 是幾個(gè)點(diǎn) * 按照優(yōu)先級(jí)劃分啟動(dòng)順序,永遠(yuǎn)確保文件樹(shù)和編輯器最快渲染出來(lái),并且光標(biāo)第一時(shí)間在編輯器內(nèi)跳動(dòng)(這意味著用戶可以開(kāi)始編輯文件了) * 測(cè)量監(jiān)控性能數(shù)據(jù),每個(gè)版本都收集盡可能多的數(shù)據(jù)來(lái)直觀的表現(xiàn)性能 * 對(duì)于出現(xiàn)的性能瓶頸快速做出改進(jìn)。

性能優(yōu)化是一個(gè)長(zhǎng)期的過(guò)程,并不是某個(gè)時(shí)間段集中精力優(yōu)化一波就高枕無(wú)憂了,你可以在 VS Code 的 issue 列表里找到一系列標(biāo)簽為 perf 和 startup-perf 相關(guān)的 issue,并且這些 issue 都有人長(zhǎng)期跟蹤解決的。

從哪開(kāi)始?

在這之前我們需要明確幾個(gè)首屏啟動(dòng)性能相關(guān)的概念,這里列舉的并不是全部,有興趣的可以自行在  Web.Dev  查找其他指標(biāo)。

| 縮寫 | 英文全稱 | 說(shuō)明 | | -- | ----- | ------ | | FCP |  First Contentful Paint | 瀏覽器渲染DOM內(nèi)容的第一個(gè)字節(jié) | | LCP |  Largest Contentful Paint  | 可是區(qū)內(nèi)最大塊的文本或圖像渲染時(shí)間 | | FID |  First Input Delay  | 用戶實(shí)現(xiàn)交互操作的相應(yīng)時(shí)間,例如點(diǎn)擊事件有反應(yīng) | | FCI |  First CPU Idle | 首次CPU空閑時(shí)間 | | TTI |  Time to Interactive  | 頁(yè)面開(kāi)始加載到穩(wěn)定可交互的時(shí)間,所有按鈕點(diǎn)擊都有反應(yīng) |

我們不一定關(guān)注以上所有的指標(biāo),但有幾個(gè)對(duì)用戶體感差異較為明顯的指標(biāo)可以重點(diǎn)關(guān)注一下,例如 LCP 、 FID 以及 TTI。

還有另一項(xiàng)指標(biāo) FMP (First Meaningful Paint 首次有效渲染時(shí)間) 不是很推薦,因?yàn)樗鼰o(wú)法直觀的識(shí)別頁(yè)面的主體內(nèi)容是否加載完成,例如某些網(wǎng)站會(huì)在有意義的內(nèi)容渲染前展示一個(gè)全屏的 Loading 動(dòng)畫,這對(duì)用戶來(lái)講顯然是沒(méi)有任何意義的,而相比之下 LCP 更為純粹,它只看頁(yè)面主體內(nèi)容、圖像是否加載完成。

這與 VS Code 的原則不謀而合,對(duì)于文本編輯器來(lái)說(shuō),性能好壞最直接的問(wèn)題就是從點(diǎn)開(kāi)圖標(biāo)到我可以輸入文本需要多久?VS Code 的答案是 1 秒 (熱啟動(dòng)在 500 毫秒左右)。

所以第一步永遠(yuǎn)是測(cè)量,不管是 console.time 還是新的 Performance API,在關(guān)鍵的節(jié)點(diǎn)添加這些性能標(biāo)記,通過(guò)大量的數(shù)據(jù)收集可以得到一個(gè)真實(shí)的性能指標(biāo)。VS Code 選擇了 Performance API ,這樣更方便匯總上報(bào)數(shù)據(jù)。運(yùn)行 Startup Performance 命令可以看到這些性能指標(biāo)的耗時(shí) (總耗時(shí)2s+, 實(shí)際上 TTI 是 977ms)。

數(shù)據(jù)收集除了能看到當(dāng)前真實(shí)的性能指標(biāo),更能幫助我們發(fā)現(xiàn)耗時(shí)花在了哪些地方。要做到這一點(diǎn),需要找到這些關(guān)鍵節(jié)點(diǎn)。VS Code 是基于 Electron ,除了常規(guī)的頁(yè)面渲染之外,還有一包括等待 Electron App Ready、創(chuàng)建窗口、LoadURL 等耗時(shí),這部分的性能有專業(yè)的團(tuán)隊(duì)來(lái)保障(Electron、V8),不需要關(guān)心太多。所以重點(diǎn)需要關(guān)心的是 UI 部分的呈現(xiàn)及可交互時(shí)間。

盡可能快地加載并執(zhí)行 JavaScript

回到我們擅長(zhǎng)的前端領(lǐng)域,當(dāng)我們談到性能優(yōu)化時(shí),總是逃不開(kāi)幾條金科玉律:

  1. 減小包體積,包括對(duì) HTML、CSS、JavaScript 代碼的壓縮等

  2. 減小 HTTP 請(qǐng)求,使用服務(wù)端 gzip 壓縮

  3. 使用 Webpack、Rollup 等現(xiàn)代構(gòu)建工具來(lái)抽離公共代碼,Code Splitting 代碼拆分等

所有這些優(yōu)化的目的,都是為了盡可能快的加載并執(zhí)行 JavaScript 代碼。在 SPA 大行其道的今天,JavaScript 加載越慢,就意味著用戶看到的白屏?xí)r間更久(于是又催生出了 SSR 這種方案)。

▐     V8 Code Cache

V8 Code Cache  的目的是減少對(duì) JavaScript 代碼的解析與編譯開(kāi)銷,我們知道 V8 使用 JIT (Just in time compilation) 來(lái)執(zhí)行 JavaScript 代碼,也就是說(shuō)在 JS 腳本執(zhí)行之前,必須對(duì)其進(jìn)行解析和編譯,這一步的開(kāi)銷是較大的。而 Code Cache 技術(shù)是在首次編譯時(shí)將結(jié)果緩存下來(lái),下一次加載相同的腳本時(shí)直接讀取磁盤上的緩存來(lái)執(zhí)行,省去了解析、編譯的過(guò)程,從而使腳本執(zhí)行更快。V8 提供了開(kāi)放的 API,因此,任何使用 V8 的軟件都可以調(diào)用該 API,同時(shí) Node.js 5.7.0 版本起 vm 模塊也提供了對(duì)該 API 的 包裝 。由于 VS Code 使用  AMD Loader  作為模塊加載器,所以內(nèi)置實(shí)現(xiàn)了  V8 Code Cache 。

不過(guò)對(duì)于大多數(shù)應(yīng)用來(lái)說(shuō),沒(méi)必要自己實(shí)現(xiàn)一遍緩存邏輯,直接使用  v8-compile-cache  ,在入口處引入 v8-compile-cache 即可。

  1. import 'v8-compile-cache'

經(jīng)過(guò)一系列的優(yōu)化,VS Code 的 JS Bundle 加載速度從一開(kāi)始的接近 1.5 秒優(yōu)化到了 0.5 秒。

生命周期,更聰明的排序

編輯器的啟動(dòng)包含許多邏輯,例如快捷鍵、編輯器、文件瀏覽器、調(diào)試器等功能的初始化與事件綁定等等,每個(gè)看起來(lái)都是非常重要的核心功能,而當(dāng)軟件體積不斷增大時(shí),這些邏輯可能會(huì)像高速公路上的車輛一樣,如果毫無(wú)秩序,每一輛車都想以最快的速度通過(guò),反而會(huì)導(dǎo)致所有車輛停滯不前,造成擁堵。

拆分生命周期的一個(gè)重要目的就是將這些核心功能的優(yōu)先級(jí)進(jìn)行排序,黃金原則就是盡可能快的讓用戶最關(guān)心的界面先渲染出來(lái)。對(duì)于 VS Code 來(lái)說(shuō),就是文件資源管理器和編輯器。VS Code 的核心功能都是通過(guò) Contribution 來(lái)注冊(cè)的。在早期的版本中,這些貢獻(xiàn)點(diǎn)會(huì)在啟動(dòng)時(shí)就全部一起進(jìn)行注冊(cè),這直接導(dǎo)致編輯器的加載被阻塞,最直觀的表現(xiàn)就是界面所有 UI 都已經(jīng)渲染出來(lái)并且可操作時(shí),編輯器內(nèi)的文本還沒(méi)有加載出來(lái)(它們可能很大)。 

拆分生命周期階段本質(zhì)上就是將這些貢獻(xiàn)點(diǎn)分階段來(lái)實(shí)例化,具體來(lái)說(shuō),VS Code 將整個(gè)啟動(dòng)的生命周期分為了四個(gè)階段

  1. Starting 應(yīng)用開(kāi)始啟動(dòng)階段,非常底層的依賴需要在該階段實(shí)例化

  2. Ready 核心服務(wù)已經(jīng)實(shí)例化完成

  3. Restored 編輯器、UI 狀態(tài)已經(jīng)恢復(fù)完成(前一次關(guān)閉時(shí)緩存的狀態(tài))

  4. Eventually 準(zhǔn)備就緒,意味著編輯器完全可用

生命周期執(zhí)行的核心代碼 ```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 { // 當(dāng)達(dá)到對(duì)應(yīng)的階段時(shí)直接實(shí)例化貢獻(xiàn)點(diǎn) if (lifecycleService.phase >= phase) { this.doInstantiateByPhase(instantiationService, phase); }

// 未達(dá)到對(duì)應(yīng)階段時(shí)一直等待 else { lifecycleService.when(phase).then(() => this.doInstantiateByPhase(instantiationService, phase)); } } ``` 

正如分享的作者 Johannes Rieken 所說(shuō),這并不是非常復(fù)雜的技術(shù)問(wèn)題,而是以一種更聰明的方式來(lái)對(duì)啟動(dòng)過(guò)程重新排序。這樣一來(lái),整體的啟動(dòng)過(guò)程會(huì)更加的有序,對(duì)于一些不是那么重要的任務(wù),將它們的優(yōu)先級(jí)靠后一些,從而確保能在第一時(shí)間將編輯器呈現(xiàn)出來(lái),使用戶進(jìn)入可以編輯的狀態(tài)。

IdleCallback

  1. // busy busy busy busy 
  2. // busy busy busy busy 
  3. // busy busy busy busy 
  4. requestIdleCallback((dealline) => { 
  5.   // idle idle idle idle 
  6.   // idle idle idle idle 
  7.   // idle idle idle idle 
  8. }) 
  9. // busy busy busy busy 
  10. // busy busy busy busy 
  11. // busy busy busy busy 

requestIdleCallback 是一個(gè)瀏覽器提供的 API,用于在 CPU 空閑時(shí)間執(zhí)行一些任務(wù)。相比 setTimeout,requestIdleCallback 的執(zhí)行時(shí)機(jī)由瀏覽器來(lái)控制,因?yàn)闉g覽器知道何時(shí)才是空閑時(shí)間。利用 requestIdleCallback,可以將一些必要但不緊急的工作延后處理,例如常見(jiàn)的一些埋點(diǎn)上報(bào)邏輯,可能會(huì)在觸發(fā)某些高頻率的交互操作時(shí)執(zhí)行,而如果將這些邏輯與事件處理放在一起,很容易影響操作體驗(yàn)。

requestIdl eCallback 可以傳入第二個(gè)參數(shù),表示超時(shí)時(shí)間。表示最晚多久以后來(lái)執(zhí)行回調(diào)函數(shù)。typescript requestIdleCallback(processPendingAnalyticsEvents, { timeout: 2000 }); `

一般來(lái)說(shuō)應(yīng)該將執(zhí)行時(shí)機(jī)交還給瀏覽器,讓瀏覽器自行決定何時(shí)調(diào)用回調(diào),如果設(shè)置了超時(shí)時(shí)間,則可能因?yàn)閳?zhí)行順序被打亂。

Perceived Performance ,讓體感更快的小技巧

對(duì)于一些耗時(shí)的確會(huì)很長(zhǎng)的操作,例如打開(kāi)一個(gè)巨大的文件,顯然即便是性能最好的的優(yōu)化手段,也無(wú)法將這種耗時(shí)降到毫秒級(jí)。但我們可以通過(guò)一些小的手段讓這種交互 感覺(jué)更快。例如在這個(gè) Case 中,點(diǎn)擊打開(kāi)一個(gè)大文件(2.5m)時(shí),先將編輯器 Tab 以及面包屑渲染出來(lái)。

除此之外,對(duì)于切換編輯器 Tab 時(shí),使用 MouseDown 而非 MouseUp 事件,一次點(diǎn)擊事件從觸發(fā) MouseDown 到 MouseUp 中間的耗時(shí)平均是50ms,這意味著在切換編輯器時(shí),鼠標(biāo)點(diǎn)擊至少 50ms 后包括 Tab 以及面包屑才會(huì)有反應(yīng)。我們可以寫一個(gè)很簡(jiǎn)單的 Demo 來(lái)觀察這兩者的區(qū)別。

例如這張截圖中,點(diǎn)擊 package.json 時(shí),文件內(nèi)容還是另一個(gè)文件,而面包屑已經(jīng)變成了 package.json。使用這種小技巧,在 VS Code 中切換編輯器時(shí),會(huì)令用戶覺(jué)得「反應(yīng)好快」, 

不建議在所有點(diǎn)擊事件觸發(fā)的地方都使用 MouseDown 來(lái)代替 MouseUp,因?yàn)閺?fù)雜的 UI 可能還需要處理如拖動(dòng)等事件,這會(huì)讓事件處理更加復(fù)雜。

最后

這篇分享的內(nèi)容沒(méi)有太多看起來(lái)非常硬核的技術(shù)手段,更多的是對(duì)當(dāng)前性能瓶頸的測(cè)量,以及更聰明的「重新排列組合」,或者說(shuō)采用了一系列使體驗(yàn)更好的策略,這對(duì)用戶體驗(yàn)的提升是巨大的。 

 

責(zé)任編輯:張燕妮 來(lái)源: 淘系技術(shù)
相關(guān)推薦

2022-03-29 13:27:22

Android優(yōu)化APP

2020-03-23 15:15:57

MySQL性能優(yōu)化數(shù)據(jù)庫(kù)

2020-07-17 19:55:50

Vue前端性能優(yōu)化

2010-07-06 09:07:09

2017-01-23 21:05:00

AndroidApp啟動(dòng)優(yōu)化

2019-12-13 10:25:08

Android性能優(yōu)化啟動(dòng)優(yōu)化

2019-08-02 11:28:45

HadoopYARN調(diào)度系統(tǒng)

2021-09-24 14:02:53

性能優(yōu)化實(shí)踐

2019-05-21 09:40:47

Elasticsear高性能 API

2022-10-28 13:41:51

字節(jié)SDK監(jiān)控

2018-06-12 15:30:07

數(shù)據(jù)庫(kù)MySQLinsert

2011-08-11 09:45:25

2023-09-25 10:02:00

GitVS Code

2022-07-15 09:20:17

性能優(yōu)化方案

2012-12-24 09:55:15

JavaJava WebJava優(yōu)化

2016-11-17 09:00:46

HBase優(yōu)化策略

2022-07-08 09:38:27

攜程酒店Flutter技術(shù)跨平臺(tái)整合

2021-02-05 05:28:31

恢復(fù)性能優(yōu)化

2014-03-19 14:34:06

JQuery高性能

2017-03-01 20:53:56

HBase實(shí)踐
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)