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

怼烎@ 2021-11-02 13:02 550阅读 0赞

第一篇: vscode源码分析【一】从源码运行vscode
第二篇:vscode源码分析【二】程序的启动逻辑,第一个窗口是如何创建的
第三篇:vscode源码分析【三】程序的启动逻辑,性能问题的追踪
第四篇:vscode源码分析【四】程序启动的逻辑,最初创建的服务

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

在入口程序的startup方法中(src\vs\code\electron-main\main.ts),有这么一句:

  1. once(lifecycleService.onWillShutdown)(() => (configurationService as ConfigurationService).dispose());

上面这句话语义好直白呀!一旦lifecycle里发生了willShutdown的事件,就执行后面的回调函数!
那我们看看lifecycle里的这个onWillShutdown(src\vs\platform\lifecycle\electron-main\lifecycleMain.ts)

  1. private readonly _onWillShutdown = this._register(new Emitter<ShutdownEvent>());
  2. readonly onWillShutdown: Event<ShutdownEvent> = this._onWillShutdown.event;

发现它是被_register注册的,这个文件里并没有_register函数,函数在它的父类Disposable里(src\vs\base\common\lifecycle.ts)
我一直以为这是资源释放的类,没想到还有事件相关的内容,哈!

  1. private readonly _store = new DisposableStore();
  2. protected _register<T extends IDisposable>(t: T): T {
  3. if ((t as any as Disposable) === this) {
  4. throw new Error('Cannot register a disposable on itself!');
  5. }
  6. return this._store.add(t);
  7. }

看来,还得看DisposableStore的add方法:

  1. public add<T extends IDisposable>(t: T): T {
  2. if (!t) {
  3. return t;
  4. }
  5. if ((t as any as DisposableStore) === this) {
  6. throw new Error('Cannot register a disposable on itself!');
  7. }
  8. markTracked(t);
  9. if (this._isDisposed) {
  10. console.warn(new Error('Registering disposable on object that has already been disposed of').stack);
  11. t.dispose();
  12. } else {
  13. this._toDispose.add(t);
  14. }
  15. return t;
  16. }

markTracked这个方法不用管,里面什么也没干!
_toDispose就是个set,用来存你传入的事件的;
另外,这个函数有个特别之处,就是你喂了它什么它就拉了什么出来!
因为我们喂了它一个Emitter的实例,那我们就去看看Emitter(src\vs\base\common\event.ts)
这是个泛型类型
有个get属性:

  1. get event(): Event<T> { //......

上面说的:

  1. this._onWillShutdown.event;

取.event的时候,执行的就是这里,它其实返回了一个方法:

  1. this._event = (listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore) => { //......

好!打住!看到这里我们先不去看这个方法的具体逻辑,
先返回头来看最开始时main.ts里的那个once方法:(src\vs\base\common\functional.ts)

  1. export function once<T extends Function>(this: any, fn: T): T {
  2. const _this = this;
  3. let didCall = false;
  4. let result: any;
  5. return function () {
  6. if (didCall) {
  7. return result;
  8. }
  9. didCall = true;
  10. result = fn.apply(_this, arguments);
  11. return result;
  12. } as any as T;
  13. }

很好理解,传入一个方法,返回一个方法,
我们知道,我们传入的是:

  1. lifecycleService.onWillShutdown

前面我们说了,它确实是一个方法;
这个once还返回了一个匿名函数;
我们通过这个匿名函数,把我们的事件处理逻辑,绑定给了:lifecycleService.onWillShutdown
这是绑定的关键代码:

  1. result = fn.apply(_this, arguments);

OK!我们再去看那个this._event返回的方法具体干了啥?!
传入的参数,listener是我们的匿名回调函数

  1. () => (configurationService as ConfigurationService).dispose()

Emitter实例的_listeners属性已经在别处初始化成了LinkedList的实例;

  1. const remove = this._listeners.push(!thisArgs ? listener : [listener, thisArgs]);

这句话把我们的匿名回调函数加到这个LinkedList中去了
好,以上是绑定事件,
我们再来看看这个事件被触发的时候是怎样的

  1. this._onWillShutdown.fire({
  2. join(promise) {
  3. if (promise) {
  4. joiners.push(promise);
  5. }
  6. }
  7. });

在这个fire方法中:

  1. for (let iter = this._listeners.iterator(), e = iter.next(); !e.done; e = iter.next()) {
  2. this._deliveryQueue.push([e.value, event]);
  3. }
  4. while (this._deliveryQueue.size > 0) {
  5. const [listener, event] = this._deliveryQueue.shift()!;
  6. try {
  7. if (typeof listener === 'function') {
  8. listener.call(undefined, event);
  9. } else {
  10. listener[0].call(listener[1], event);
  11. }
  12. } catch (e) {
  13. onUnexpectedError(e);
  14. }
  15. }

循环派发了所有注册的事件

转载于:https://www.cnblogs.com/liulun/p/11047359.html

发表评论

表情:
评论列表 (有 0 条评论,550人围观)

还没有评论,来说两句吧...

相关阅读

    相关 事件分发机制

    基础认知 当用户触摸屏幕时(View或ViewGroup派生的控件),将产生点击事件(Touch事件)。 主要发生的Touch事件有如下四种: MotionEve