zoukankan      html  css  js  c++  java
  • vscode源码分析【四】程序启动的逻辑,最初创建的服务

    第一篇: vscode源码分析【一】从源码运行vscode
    第二篇:vscode源码分析【二】程序的启动逻辑,第一个窗口是如何创建的
    第三篇:vscode源码分析【三】程序的启动逻辑,性能问题的追踪
    在第一节中提到的startup函数里(srcvscodeelectron-mainmain.ts)
    有一个createServices的调用:

    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(srcvsplatforminstantiationcommonserviceCollection.ts)
    这个ServiceCollection内部其实就是一个map对象;不用细说;

    我们先看看这些service都是干嘛的

    运行环境服务:EnvironmentService

    路径:srcvsplatformenvironment odeenvironmentService.ts
    这是一个工具类,
    通过这个类可以获取程序的:
    启动目录、日志目录、操作系统、配置文件目录、快捷键绑定配置路径....
    非常多!

    多路日志服务:MultiplexLogService

    路径:srcvsplatformlogcommonlog.ts
    默认是用的控制台输出日志(ConsoleLogMainService)
    也是一个工具类
    包含trace(查看调用堆栈的),debug,info,warn,error,critical
    还有dispose(释放日志服务,进程退出的时候回被调用)和setLevel(设置日志级别)的方法;
    在同一个文件里,除了ConsoleLogMainService,
    还实现了其他几种日志记录方式,不多做介绍了;

    配置服务:ConfigurationService

    路径:srcvsplatformconfiguration odeconfigurationService.ts
    从运行环境服务(environmentService)里,拿到配置文件的路径
    读出配置文件的内容,然后提供配置项的读写功能;
    配置项变更的时候,会有相应的事件触发出来;

    生命周期服务:LifecycleService

    路径:srcvsplatformlifecycleelectron-mainlifecycleMain.ts
    在这里监听了一系列的electron的事件
    比如:
    before-quit、window-all-closed、will-quit等
    事件被触发的时候,做了下面一些事情
    记日志、屏蔽electron默认的处理逻辑、执行自己的逻辑

    状态服务:StateService

    路径:srcvsplatformstate odestateService.ts
    在storage.json里记录一些与程序运行状态有关的键值对(也可以删除)

    请求服务:RequestService

    路径:srcvsplatform equestelectron-main equestService.ts
    使用electron提供的net.request方法,发起请求(支持代理和SSL)

    诊断服务:DiagnosticsService

    路径:srcvsplatformdiagnosticselectron-maindiagnosticsService.ts
    根据不同的操作系统,计算CPU消耗、内存消耗、GPU消耗等

    界面主题服务:ThemeMainService

    路径:srcvsplatform hemeelectron-main hemeMainService.ts
    获取背景色、设置背景色
    数据通过stateService保存

    程序签名服务:SignService

    路径:srcvsplatformlifecycleelectron-mainlifecycleMain.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中完成的(srcvscodeelectron-mainmain.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]);

    可以看到这个方法里创建了一大堆目录;
    创建目录的方法是:(srcvsase odepfs.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(srcvsplatforminstantiationcommondescriptors.ts)
    这里我们解释一下SyncDescriptor,是个简单的泛型类型;
    一个它的实例,可以持有一个类型(传入构造函数的类型),这个类型可以等到用的时候再实例化;



     

  • 相关阅读:
    ibmmq 性能测试
    zabbix-agent 安装
    关于dubbo接口性能测试
    关于vyos 防火墙配置
    appium自动化的工作原理(1)
    unittest如何在循环遍历一条用例时生成多个测试结果
    在Linux中#!/usr/bin/python之后把后面的代码当成程序来执行。 但是在windows中用IDLE编程的话#后面的都是注释,之后的代码都被当成文本了。 该怎么样才能解决这个问题呢?
    Cookie和Session的区别详解
    点单登录原理和java实现简单的单点登录
    new一个JAVA对象的时候,内存是怎么分配的?
  • 原文地址:https://www.cnblogs.com/liulun/p/11045804.html
Copyright © 2011-2022 走看看