第一篇: vscode源碼分析【一】從源碼運行vscode
第二篇:vscode源碼分析【二】程序的啓動邏輯,第一個窗口是如何建立的
第三篇:vscode源碼分析【三】程序的啓動邏輯,性能問題的追蹤
在第一節中提到的startup函數裏(src\vs\code\electron-main\main.ts)
有一個createServices的調用:html
const services = new ServiceCollection(); const environmentService = new EnvironmentService(args, process.execPath); const instanceEnvironment = this.patchEnvironment(environmentService); // Patch `process.env` with the instance's environment services.set(IEnvironmentService, environmentService); const logService = new MultiplexLogService([new ConsoleLogMainService(getLogLevel(environmentService)), bufferLogService]); process.once('exit', () => logService.dispose()); services.set(ILogService, logService); services.set(IConfigurationService, new ConfigurationService(environmentService.settingsResource)); services.set(ILifecycleService, new SyncDescriptor(LifecycleService)); services.set(IStateService, new SyncDescriptor(StateService)); services.set(IRequestService, new SyncDescriptor(RequestService)); services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService)); services.set(IThemeMainService, new SyncDescriptor(ThemeMainService)); services.set(ISignService, new SyncDescriptor(SignService)); return [new InstantiationService(services, true), instanceEnvironment];
在這個方法裏,首先建立了一個ServiceCollection(src\vs\platform\instantiation\common\serviceCollection.ts)
這個ServiceCollection內部其實就是一個map對象;不用細說;
咱們先看看這些service都是幹嗎的node
路徑:src\vs\platform\environment\node\environmentService.ts
這是一個工具類,
經過這個類能夠獲取程序的:
啓動目錄、日誌目錄、操做系統、配置文件目錄、快捷鍵綁定配置路徑....
很是多!json
路徑:src\vs\platform\log\common\log.ts
默認是用的控制檯輸出日誌(ConsoleLogMainService)
也是一個工具類
包含trace(查看調用堆棧的),debug,info,warn,error,critical
還有dispose(釋放日誌服務,進程退出的時候回被調用)和setLevel(設置日誌級別)的方法;
在同一個文件裏,除了ConsoleLogMainService,
還實現了其餘幾種日誌記錄方式,很少作介紹了;緩存
路徑:src\vs\platform\configuration\node\configurationService.ts
從運行環境服務(environmentService)裏,拿到配置文件的路徑
讀出配置文件的內容,而後提供配置項的讀寫功能;
配置項變動的時候,會有相應的事件觸發出來;electron
路徑:src\vs\platform\lifecycle\electron-main\lifecycleMain.ts
在這裏監聽了一系列的electron的事件
好比:
before-quit、window-all-closed、will-quit等
事件被觸發的時候,作了下面一些事情
記日誌、屏蔽electron默認的處理邏輯、執行本身的邏輯async
路徑:src\vs\platform\state\node\stateService.ts
在storage.json裏記錄一些與程序運行狀態有關的鍵值對(也能夠刪除)函數
路徑:src\vs\platform\request\electron-main\requestService.ts
使用electron提供的net.request方法,發起請求(支持代理和SSL)工具
路徑:src\vs\platform\diagnostics\electron-main\diagnosticsService.ts
根據不一樣的操做系統,計算CPU消耗、內存消耗、GPU消耗等源碼分析
路徑:src\vs\platform\theme\electron-main\themeMainService.ts
獲取背景色、設置背景色
數據經過stateService保存post
路徑:src\vs\platform\lifecycle\electron-main\lifecycleMain.ts
這個服務爲程序的簽名提供幫助
緩存了一個vsda的import,目的是爲了解決簽名時的一個BUG
這個服務比較特殊,不是在本文一開始所講的代碼裏設置的
前面的代碼中有這麼一行:
return [new InstantiationService(services, true), instanceEnvironment];
這個服務就是在它自身的內部保存到ServiceCollection
constructor(services: ServiceCollection = new ServiceCollection(), strict: boolean = false, parent?: InstantiationService) { this._services = services; this._strict = strict; this._parent = parent; this._services.set(IInstantiationService, this); }
這個服務提供了反射、實例化的一些方法;
用於建立具體的類型的實例
服務的對象建立出來以後,有些服務須要完成初始化才能使用
這是在main.ts的initServices中完成的(src\vs\code\electron-main\main.ts)
// Environment service (paths) const environmentServiceInitialization = Promise.all<void | undefined>([ environmentService.extensionsPath, environmentService.nodeCachedDataDir, environmentService.logsPath, environmentService.globalStorageHome, environmentService.workspaceStorageHome, environmentService.backupHome ].map((path): undefined | Promise<void> => path ? mkdirp(path) : undefined)); // Configuration service const configurationServiceInitialization = configurationService.initialize(); // State service const stateServiceInitialization = stateService.init(); return Promise.all([environmentServiceInitialization, configurationServiceInitialization, stateServiceInitialization]);
能夠看到這個方法裏建立了一大堆目錄;
建立目錄的方法是:(src\vs\base\node\pfs.ts)
const mkdir = async () => { try { await promisify(fs.mkdir)(path, mode); } catch (error) { // ENOENT: a parent folder does not exist yet if (error.code === 'ENOENT') { return Promise.reject(error); } // Any other error: check if folder exists and // return normally in that case if its a folder try { const fileStat = await stat(path); if (!fileStat.isDirectory()) { return Promise.reject(new Error(`'${path}' exists and is not a directory.`)); } } catch (statError) { throw error; // rethrow original error } } };
另外: 最後幾個服務的建立(嚴格說尚未建立)都用到了SyncDescriptor(src\vs\platform\instantiation\common\descriptors.ts) 這裏咱們解釋一下SyncDescriptor,是個簡單的泛型類型; 一個它的實例,能夠持有一個類型(傳入構造函數的類型),這個類型能夠等到用的時候再實例化;