vscode源碼分析【四】程序啓動的邏輯,最初建立的服務

第一篇: 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

運行環境服務:EnvironmentService

路徑:src\vs\platform\environment\node\environmentService.ts
這是一個工具類,
經過這個類能夠獲取程序的:
啓動目錄、日誌目錄、操做系統、配置文件目錄、快捷鍵綁定配置路徑....
很是多!json

多路日誌服務:MultiplexLogService

路徑:src\vs\platform\log\common\log.ts
默認是用的控制檯輸出日誌(ConsoleLogMainService)
也是一個工具類
包含trace(查看調用堆棧的),debug,info,warn,error,critical
還有dispose(釋放日誌服務,進程退出的時候回被調用)和setLevel(設置日誌級別)的方法;
在同一個文件裏,除了ConsoleLogMainService,
還實現了其餘幾種日誌記錄方式,很少作介紹了;緩存

配置服務:ConfigurationService

路徑:src\vs\platform\configuration\node\configurationService.ts
從運行環境服務(environmentService)裏,拿到配置文件的路徑
讀出配置文件的內容,而後提供配置項的讀寫功能;
配置項變動的時候,會有相應的事件觸發出來;electron

生命週期服務:LifecycleService

路徑:src\vs\platform\lifecycle\electron-main\lifecycleMain.ts
在這裏監聽了一系列的electron的事件
好比:
before-quit、window-all-closed、will-quit等
事件被觸發的時候,作了下面一些事情
記日誌、屏蔽electron默認的處理邏輯、執行本身的邏輯async

狀態服務:StateService

路徑:src\vs\platform\state\node\stateService.ts
在storage.json裏記錄一些與程序運行狀態有關的鍵值對(也能夠刪除)函數

請求服務:RequestService

路徑:src\vs\platform\request\electron-main\requestService.ts
使用electron提供的net.request方法,發起請求(支持代理和SSL)工具

診斷服務:DiagnosticsService

路徑:src\vs\platform\diagnostics\electron-main\diagnosticsService.ts
根據不一樣的操做系統,計算CPU消耗、內存消耗、GPU消耗等源碼分析

界面主題服務:ThemeMainService

路徑:src\vs\platform\theme\electron-main\themeMainService.ts
獲取背景色、設置背景色
數據經過stateService保存post

程序簽名服務:SignService

路徑:src\vs\platform\lifecycle\electron-main\lifecycleMain.ts
這個服務爲程序的簽名提供幫助
緩存了一個vsda的import,目的是爲了解決簽名時的一個BUG

實例化服務:InstantiationService

這個服務比較特殊,不是在本文一開始所講的代碼裏設置的
前面的代碼中有這麼一行:

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,是個簡單的泛型類型; 一個它的實例,能夠持有一個類型(傳入構造函數的類型),這個類型能夠等到用的時候再實例化;  

相關文章
相關標籤/搜索