zoukankan      html  css  js  c++  java
  • vscode源码分析【五】事件分发机制

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

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

    在入口程序的startup方法中(srcvscodeelectron-mainmain.ts),有这么一句:

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

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

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

    发现它是被_register注册的,这个文件里并没有_register函数,函数在它的父类Disposable里(srcvsasecommonlifecycle.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(srcvsasecommonevent.ts)
    这是个泛型类型
    有个get属性:

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

    上面说的:

    this._onWillShutdown.event;

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

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

    好!打住!看到这里我们先不去看这个方法的具体逻辑,
    先返回头来看最开始时main.ts里的那个once方法:(srcvsasecommonfunctional.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);
    				}
    			}

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







     

  • 相关阅读:
    Address already in use: JVM_Bind 端口被占
    Excel PDF预览 excel导出
    js 判断日期是否节假日
    2020 idea的RunDashboard怎么显示出来
    sql server if else
    IDEA热部署总是失败的解决
    java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
    IOS开发 strong,weak,retain,assign,copy nomatic 等的区别与作用
    NSOperationQueue与GCD的使用原则和场景
    View加载过程
  • 原文地址:https://www.cnblogs.com/liulun/p/11047359.html
Copyright © 2011-2022 走看看