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

循環派發了所有注冊的事件







 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM