vscode源码分析【六】服务实例化和单例的实现

细心的读者可能会发现,在第四篇文章中的createService方法中,并没有把所有的服务实例化,下面这些服务,只是记了他们的类型: src\vs\code\electron-main\main.ts

		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));

SyncDescriptor负责记录这些服务的类型,以供后续使用 (src\vs\platform\instantiation\common\descriptors.ts)

export class SyncDescriptor<T> {
	readonly ctor: any;
	readonly staticArguments: any[];
	readonly supportsDelayedInstantiation: boolean;
	constructor(ctor: new (...args: any[]) => T, staticArguments: any[] = [], supportsDelayedInstantiation: boolean = false) {
		this.ctor = ctor;
		this.staticArguments = staticArguments;
		this.supportsDelayedInstantiation = supportsDelayedInstantiation;
	}
}

接下来,main.ts的startup方法内,就实例化了这些服务

			await instantiationService.invokeFunction(async accessor => {
				const environmentService = accessor.get(IEnvironmentService);
				const configurationService = accessor.get(IConfigurationService);
				const stateService = accessor.get(IStateService);
				try {
					await this.initServices(environmentService, configurationService as ConfigurationService, stateService as StateService);
				} catch (error) {

					// Show a dialog for errors that can be resolved by the user
					this.handleStartupDataDirError(environmentService, error);

					throw error;
				}
			});

这里accessor的get方法如下:(src\vs\platform\instantiation\common\instantiationService.ts)

				get: <T>(id: ServiceIdentifier<T>, isOptional?: typeof optional) => {

					if (_done) {
						throw illegalState('service accessor is only valid during the invocation of its target method');
					}

					const result = this._getOrCreateServiceInstance(id, _trace);
					if (!result && isOptional !== optional) {
						throw new Error(`[invokeFunction] unknown service '${id}'`);
					}
					return result;
				}

有个_getOrCreateServiceInstance方法:

	private _getOrCreateServiceInstance<T>(id: ServiceIdentifier<T>, _trace: Trace): T {
		let thing = this._getServiceInstanceOrDescriptor(id);
		if (thing instanceof SyncDescriptor) {
			return this._createAndCacheServiceInstance(id, thing, _trace.branch(id, true));
		} else {
			_trace.branch(id, false);
			return thing;
		}
	}

你发现,如果它想获取的对象是SyncDescriptor类型的,就会创建并缓存相应的对象 这个方法_createAndCacheServiceInstance负责创建对象的实例(暂时先不解释) 下次获取这个对象的时候,就直接从缓存中获取了

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏liulun

vscode源码分析【二】程序的启动逻辑,第一个窗口是如何创建的

electron是分主进程和渲染进程的; 渲染进程是主进程启动的; ./out/main.js显然这就是主进程的入口程序; 确实不假 但别着急去分析这个...

27820
来自专栏code秘密花园

[现场实录] VueConf 2019 尤雨溪演讲总结

Chrome DevTools 有约 90 万的周活用户,React 相比有 160 万。Evan 推荐用 Chrome DevTools 来预测 Vue 的项...

20010
来自专栏前端加油站

angular4实战(3) 插件引入及封装

版权声明:本文为博主原创文章,未经博主允许不得转载。 ...

8530
来自专栏liulun

vscode源码分析【五】事件分发机制

在上一篇中,我们看到lifecycleService监听了很多electron原生的事件, 监听了之后,一旦事件被触发,vscode是怎么派发这些事件的呢?...

22440
来自专栏liulun

vscode源码分析【四】程序启动的逻辑,最初创建的服务

在第一节中提到的startup函数里(src\vs\code\electron-main\main.ts) 有一个createServices的调用:

16440
来自专栏全栈修炼

[现场实录] VueConf 2019 尤雨溪演讲总结

距离参加 VueConf 第一届大会已经很久了,yubo 的介绍一如既往地有意思,是他的努力保持了大会热情的社区氛围!另一个彩蛋就是 Evan You 带了自己...

18210
来自专栏进击的全栈

AST in TypeScript 实践

  最近参与了一个 Node 项目脚手架的开发工作,为了提高编码效率,导师提议写一个 VSCode 的插件,功能上大体有点像 snippets 代码段,但比 s...

858430
来自专栏全栈开发小账本

Typescript中类型错误解决方案

13720
来自专栏葡萄城控件技术团队

2019 Vue开发指南:你都需要学点啥?

如果您是Vue开发的新手,您可能已经听过很多关于它的专业术语了,例如:单页面应用程序、异步组件、服务器端呈现等。

11530

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励