vscode源码分析【五】事件分发机制
第一篇: vscode源码分析【一】从源码运行vscode
第二篇:vscode源码分析【二】程序的启动逻辑,第一个窗口是如何创建的
第三篇:vscode源码分析【三】程序的启动逻辑,性能问题的追踪
第四篇:vscode源码分析【四】程序启动的逻辑,最初创建的服务
在上一篇中,我们看到lifecycleService监听了很多electron原生的事件,
监听了之后,一旦事件被触发,vscode是怎么派发这些事件的呢?
在入口程序的startup方法中(src\vs\code\electron-main\main.ts),有这么一句:
once(lifecycleService.onWillShutdown)(() => (configurationService as ConfigurationService).dispose());
上面这句话语义好直白呀!一旦lifecycle里发生了willShutdown的事件,就执行后面的回调函数!
那我们看看lifecycle里的这个onWillShutdown(src\vs\platform\lifecycle\electron-main\lifecycleMain.ts)
private readonly _onWillShutdown = this._register(new Emitter<ShutdownEvent>());
readonly onWillShutdown: Event<ShutdownEvent> = this._onWillShutdown.event;
发现它是被_register注册的,这个文件里并没有_register函数,函数在它的父类Disposable里(src\vs\base\common\lifecycle.ts)
我一直以为这是资源释放的类,没想到还有事件相关的内容,哈!
private readonly _store = new DisposableStore();
protected _register<T extends IDisposable>(t: T): T {
if ((t as any as Disposable) === this) {
throw new Error('Cannot register a disposable on itself!');
}
return this._store.add(t);
}
看来,还得看DisposableStore的add方法:
public add<T extends IDisposable>(t: T): T {
if (!t) {
return t;
}
if ((t as any as DisposableStore) === this) {
throw new Error('Cannot register a disposable on itself!');
}
markTracked(t);
if (this._isDisposed) {
console.warn(new Error('Registering disposable on object that has already been disposed of').stack);
t.dispose();
} else {
this._toDispose.add(t);
}
return t;
}
markTracked这个方法不用管,里面什么也没干!
_toDispose就是个set,用来存你传入的事件的;
另外,这个函数有个特别之处,就是你喂了它什么它就拉了什么出来!
因为我们喂了它一个Emitter的实例,那我们就去看看Emitter(src\vs\base\common\event.ts)
这是个泛型类型
有个get属性:
get event(): Event<T> { //......
上面说的:
this._onWillShutdown.event;
取.event的时候,执行的就是这里,它其实返回了一个方法:
this._event = (listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore) => { //......
好!打住!看到这里我们先不去看这个方法的具体逻辑,
先返回头来看最开始时main.ts里的那个once方法:(src\vs\base\common\functional.ts)
export function once<T extends Function>(this: any, fn: T): T {
const _this = this;
let didCall = false;
let result: any;
return function () {
if (didCall) {
return result;
}
didCall = true;
result = fn.apply(_this, arguments);
return result;
} as any as T;
}
很好理解,传入一个方法,返回一个方法,
我们知道,我们传入的是:
lifecycleService.onWillShutdown
前面我们说了,它确实是一个方法;
这个once还返回了一个匿名函数;
我们通过这个匿名函数,把我们的事件处理逻辑,绑定给了:lifecycleService.onWillShutdown
这是绑定的关键代码:
result = fn.apply(_this, arguments);
OK!我们再去看那个this._event返回的方法具体干了啥?!
传入的参数,listener是我们的匿名回调函数
() => (configurationService as ConfigurationService).dispose()
Emitter实例的_listeners属性已经在别处初始化成了LinkedList的实例;
const remove = this._listeners.push(!thisArgs ? listener : [listener, thisArgs]);
这句话把我们的匿名回调函数加到这个LinkedList中去了
好,以上是绑定事件,
我们再来看看这个事件被触发的时候是怎样的
this._onWillShutdown.fire({
join(promise) {
if (promise) {
joiners.push(promise);
}
}
});
在这个fire方法中:
for (let iter = this._listeners.iterator(), e = iter.next(); !e.done; e = iter.next()) {
this._deliveryQueue.push([e.value, event]);
}
while (this._deliveryQueue.size > 0) {
const [listener, event] = this._deliveryQueue.shift()!;
try {
if (typeof listener === 'function') {
listener.call(undefined, event);
} else {
listener[0].call(listener[1], event);
}
} catch (e) {
onUnexpectedError(e);
}
}
循环派发了所有注册的事件
vscode源码分析【五】事件分发机制的更多相关文章
- vscode源码分析【九】窗口里的主要元素
第一篇: vscode源码分析[一]从源码运行vscode 第二篇:vscode源码分析[二]程序的启动逻辑,第一个窗口是如何创建的 第三篇:vscode源码分析[三]程序的启动逻辑,性能问题的追踪 ...
- vscode源码分析【八】加载第一个画面
第一篇: vscode源码分析[一]从源码运行vscode 第二篇:vscode源码分析[二]程序的启动逻辑,第一个窗口是如何创建的 第三篇:vscode源码分析[三]程序的启动逻辑,性能问题的追踪 ...
- vscode源码分析【七】主进程启动消息通信服务
第一篇: vscode源码分析[一]从源码运行vscode 第二篇:vscode源码分析[二]程序的启动逻辑,第一个窗口是如何创建的 第三篇:vscode源码分析[三]程序的启动逻辑,性能问题的追踪 ...
- vscode源码分析【六】服务实例化和单例的实现
第一篇: vscode源码分析[一]从源码运行vscode 第二篇:vscode源码分析[二]程序的启动逻辑,第一个窗口是如何创建的 第三篇:vscode源码分析[三]程序的启动逻辑,性能问题的追踪 ...
- vscode源码分析【四】程序启动的逻辑,最初创建的服务
第一篇: vscode源码分析[一]从源码运行vscode 第二篇:vscode源码分析[二]程序的启动逻辑,第一个窗口是如何创建的 第三篇:vscode源码分析[三]程序的启动逻辑,性能问题的追踪 ...
- vscode源码分析【三】程序的启动逻辑,性能问题的追踪
第一篇: vscode源码分析[一]从源码运行vscode 第二篇:vscode源码分析[二]程序的启动逻辑,第一个窗口是如何创建的 启动追踪 代码文件:src\main.js 如果指定了特定的启动参 ...
- Solr4.8.0源码分析(19)之缓存机制(二)
Solr4.8.0源码分析(19)之缓存机制(二) 前文<Solr4.8.0源码分析(18)之缓存机制(一)>介绍了Solr缓存的生命周期,重点介绍了Solr缓存的warn过程.本节将更深 ...
- Solr4.8.0源码分析(18)之缓存机制(一)
Solr4.8.0源码分析(18)之缓存机制(一) 前文在介绍commit的时候具体介绍了getSearcher()的实现,并提到了Solr的预热warn.那么本文开始将详细来学习下Solr的缓存机制 ...
- monkey源码分析之事件注入方法变化
在上一篇文章<Monkey源码分析之事件注入>中,我们看到了monkey在注入事件的时候用到了<Monkey源码分析番外篇之Android注入事件的三种方法比较>中的第一种方法 ...
随机推荐
- iOS引导页(开局滚动效果)
参考链接1:https://jingyan.baidu.com/article/4dc40848a341dfc8d846f152.html 参考链接2:https://www.cnblogs.com/ ...
- 中小后台系统UI框架--EasyUI
后台开发人员不擅长前端UI界面,而小型软件公司没有专职美工岗位,开发人员只能借助开源UI框架,复用已有组件,完成用户操作界面.EasyUI是基于jQuery的UI插件集合体,可帮助开发者轻松构建网页. ...
- 12c新特性 在线操作数据文件
我们都知道,oracle pre-12c之前,若是想要把一个数据文件改名或者迁移, 必须在归档模式下先把这个数据文件offline之后, 然后进行OS上的copy或者rename 操作, 最后在sql ...
- nginx 校验及重启
#查询nginx所在路径 [centos find 查询文件](https://www.cnblogs.com/codeWorldCodeHeart/p/12049262.html) #校验如下 /u ...
- [Go]TCP服务中增加消息队列与工作池
之前的处理中每一个连接都会创建一个主groutine , 每个连接中的主groutine中创建出读groutine 和写groutine 每个连接处理业务再单独开出一个groutine ,这样如果有1 ...
- shell 脚本里的$(( ))、$( )、``与${ }的区别
shell 脚本里的命令执行 1. 在bash中,$( )与` `(反引号)都是用来作命令替换的. 命令替换与变量替换差不多,都是用来重组命令行的,先完成引号里的命令行,然后将其结果替换出来,再重组 ...
- VSCode+C++环境搭建
date: 2019-10-05 VSCode+C++环境搭建 其实并不完整,毕竟我也只是一个OIer,并不会很高深的东西.(众所周知,OIer主业是软件开发) 安装VSCode 下载安装包 这个很简 ...
- 编译原理:直接推导、间接推导、n次推导、规范推导
直接推导,直接运用规则进行的推导 间接推导.n次推导 有两种符号 第一种是,表示多次运用直接推导 第二种是,表示零次或多次运用直接推导 n表示中间的步骤数 规范推导 其实就是最右推导
- PAT 1012 The Best Rank 排序
To evaluate the performance of our first year CS majored students, we consider their grades of three ...
- ASP.NET MVC5基础-控制器(Controller)详解
在上文ASP.NET MVC5基础 – MVC文件架构中我们简单了解了下控制器Controller的作用,本文我将详细介绍控制器Controller的使用方法. Controller的运行过程 上文我 ...