第一篇: vscode源碼分析【一】從源碼運行vscode
第二篇:vscode源碼分析【二】程序的啓動邏輯,第一個窗口是如何建立的
第三篇:vscode源碼分析【三】程序的啓動邏輯,性能問題的追蹤
第四篇:vscode源碼分析【四】程序啓動的邏輯,最初建立的服務
第五篇:vscode源碼分析【五】事件分發機制
第六篇:vscode源碼分析【六】服務實例化和單例的實現
在mian.ts中的doStartup方法裏,建立了一個命名管道服務
(src\vs\code\electron-main\main.ts)html
server = await serve(environmentService.mainIPCHandle); once(lifecycleService.onWillShutdown)(() => server.dispose());
傳入的environmentService.mainIPCHandle是命名管道的識別路徑,
一個有規則的字符串,規則以下:node
function getWin32IPCHandle(userDataPath: string, type: string): string { const scope = crypto.createHash('md5').update(userDataPath).digest('hex'); return `\\\\.\\pipe\\${scope}-${pkg.version}-${type}-sock`; }
注意:每次啓動程序,取這個字符串的時候,都會得到一樣的值(並且這個值是會被緩存起來的);
之後監聽消息、發送消息,都根據這個字符串來;
建立服務的代碼(serve):es6
export function serve(hook: any): Promise<Server> { return new Promise<Server>((c, e) => { const server = createServer(); server.on('error', e); server.listen(hook, () => { server.removeListener('error', e); c(new Server(server)); }); }); }
這個方法返回了一個Promise的對象,
c和e是Promise的參數,c表明成功時的回調,e表明失敗時的回調(有點相似es6的Promise)
匿名函數內createServer就是nodejs裏的原生接口,
Server類綁定了鏈接和斷開的事件,暫時不細說;
回頭看看main.ts startup方法裏有這麼一句:windows
instantiationService.createInstance(CodeApplication, mainIpcServer, instanceEnvironment).startup();
這句顯然是建立了CodeApplication的實例,而後執行了實例的startup方法
注意:建立這個實例的時候,把咱們前面建立的mainIpcServer傳遞進去了;
CodeApplication(src\vs\code\electron-main\app.ts)的startup方法,還啓動了Electron的IPCServer緩存
const electronIpcServer = new ElectronIPCServer();
vscode把electron默認的通訊機制也接入到了本身的事件體系內,有消息過來,會觸發事件;
具體先不細說,後面再講.
接着就跳轉到同類型裏的openFirstWindow方法(是否是很熟悉,咱們在第一篇文章中講到過這裏)
在這裏,給這兩個服務(mainIpcServer和electronIpcServer ),建立了一堆信道:app
const launchService = accessor.get(ILaunchService); const launchChannel = new LaunchChannel(launchService); this.mainIpcServer.registerChannel('launch', launchChannel); const updateService = accessor.get(IUpdateService); const updateChannel = new UpdateChannel(updateService); electronIpcServer.registerChannel('update', updateChannel); const issueService = accessor.get(IIssueService); const issueChannel = new IssueChannel(issueService); electronIpcServer.registerChannel('issue', issueChannel); const workspacesService = accessor.get(IWorkspacesMainService); const workspacesChannel = new WorkspacesChannel(workspacesService); electronIpcServer.registerChannel('workspaces', workspacesChannel); const windowsService = accessor.get(IWindowsService); const windowsChannel = new WindowsChannel(windowsService); electronIpcServer.registerChannel('windows', windowsChannel); sharedProcessClient.then(client => client.registerChannel('windows', windowsChannel)); const menubarService = accessor.get(IMenubarService); const menubarChannel = new MenubarChannel(menubarService); electronIpcServer.registerChannel('menubar', menubarChannel); const urlService = accessor.get(IURLService); const urlChannel = new URLServiceChannel(urlService); electronIpcServer.registerChannel('url', urlChannel); const storageMainService = accessor.get(IStorageMainService); const storageChannel = this._register(new GlobalStorageDatabaseChannel(this.logService, storageMainService as StorageMainService)); electronIpcServer.registerChannel('storage', storageChannel); const logLevelChannel = new LogLevelSetterChannel(accessor.get(ILogService)); electronIpcServer.registerChannel('loglevel', logLevelChannel);
有存儲、日誌、菜單欄、工做臺、升級.....等等
主要的通訊仍是用electronIpcServer 來乾的,mainIpcServer只有一個launch信道;
下面咱們看看消息是怎麼傳遞的
咱們隨便打開一個信道的類型(src\vs\platform\windows\node\windowsIpc.ts)
它有兩個主要的函數,listen和call,electron
listen(_: unknown, event: string): Event<any> { switch (event) { case 'onWindowOpen': return this.onWindowOpen; case 'onWindowFocus': return this.onWindowFocus; case 'onWindowBlur': return this.onWindowBlur; case 'onWindowMaximize': return this.onWindowMaximize; case 'onWindowUnmaximize': return this.onWindowUnmaximize; case 'onRecentlyOpenedChange': return this.onRecentlyOpenedChange; } throw new Error(`Event not found: ${event}`); }
call(_: unknown, command: string, arg?: any): Promise<any> { switch (command) { case 'pickFileFolderAndOpen': return this.service.pickFileFolderAndOpen(arg); case 'pickFileAndOpen': return this.service.pickFileAndOpen(arg); case 'pickFolderAndOpen': return this.service.pickFolderAndOpen(arg); case 'pickWorkspaceAndOpen': return this.service.pickWorkspaceAndOpen(arg); case 'showMessageBox': return this.service.showMessageBox(arg[0], arg[1]); case 'showSaveDialog': return this.service.showSaveDialog(arg[0], arg[1]); case 'showOpenDialog': return this.service.showOpenDialog(arg[0], arg[1]); //......
消息來了,進入listen函數,發送消息,進入call函數;
注意,消息來了,觸發的也不是他本身的方法,咱們看看它的構造函數:函數
constructor(private service: IWindowsService) { this.onWindowOpen = Event.buffer(service.onWindowOpen, true); this.onWindowFocus = Event.buffer(service.onWindowFocus, true); this.onWindowBlur = Event.buffer(service.onWindowBlur, true); this.onWindowMaximize = Event.buffer(service.onWindowMaximize, true); this.onWindowUnmaximize = Event.buffer(service.onWindowUnmaximize, true); this.onRecentlyOpenedChange = Event.buffer(service.onRecentlyOpenedChange, true); }
看到沒,觸發的實際上是一個事件,事件是關聯到service實例的;
這個實例是這樣建立的:源碼分析
const windowsService = accessor.get(IWindowsService);
具體的代碼在:src\vs\platform\windows\electron-browser\windowsService.ts
post