vscode原始碼分析【五】事件分發機制

liulun發表於2019-06-18

第一篇: 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);
				}
			}

迴圈派發了所有註冊的事件







 

相關文章