在上一篇中,我們一起分析了 VS Code 整體的代碼架構,了解了 VS Code 是由前后端分離的方式開發的,且無論前端是基于 electron 還是 web,后端是本地還是云端,其呼叫方式并無不同,
這樣的架構下,前后端的通信方式是如何實作的呢?本篇我們將一起來探究 VS Code For Web 的行程間通信方式,
行程通信與呼叫方式
行程間通信協議
對于多行程架構的專案,行程之間的通信會通過行程間呼叫 (Inter Process Calling, IPC),VSCode 中自己設計了專門的 IPC 模塊來實作通信,代碼位于 src/vs/base/parts/ipc,
export const enum RequestType {
Promise = 100,
PromiseCancel = 101,
EventListen = 102,
EventDispose = 103
}
從 enum type 可以看出,VSCode 的 IPC 模塊同時支持兩種呼叫方式,一種是基于 Promise 的呼叫實作, 另一種是通過 Event Emitter/Listener 的那一套事件監聽機制來實作,
以事件監聽機制為例,VSCode 中采用 vscode-jsonrpc 這個包來封裝實作,呼叫方式如下:
import * as cp from 'child_process';
import * as rpc from 'vscode-jsonrpc/node';
let childProcess = cp.spawn(...);
// Use stdin and stdout for communication:
let connection = rpc.createMessageConnection(
new rpc.StreamMessageReader(childProcess.stdout),
new rpc.StreamMessageWriter(childProcess.stdin));
let notification = new rpc.NotificationType<string, void>('testNotification');
connection.listen();
connection.sendNotification(notification, 'Hello World');
服務端呼叫也采用類似的包裝:
import * as rpc from 'vscode-jsonrpc/node';
let connection = rpc.createMessageConnection(
new rpc.StreamMessageReader(process.stdin),
new rpc.StreamMessageWriter(process.stdout));
let notification = new rpc.NotificationType<string, void>('testNotification');
connection.onNotification(notification, (param: string) => {
console.log(param); // This prints Hello World
});
connection.listen();
行程間通信單元
為了實作客戶端與服務端之間的點對點通信,我們需要一個最小單元來實作訊息的呼叫與監聽,在 VSCode 中,這個最小單元即為 Channel,
/**
* An `IChannel` is an abstraction over a collection of commands.
* You can `call` several commands on a channel, each taking at
* most one single argument. A `call` always returns a promise
* with at most one single return value.
*/
export interface IChannel {
call<T>(command: string, arg?: any, cancellationToken?: CancellationToken): Promise<T>;
listen<T>(event: string, arg?: any): Event<T>;
}
每次通信程序,需要客戶端與服務端處于同一個 Channel 中,
行程間通信建連
在 VSCode 中,客戶端與服務端之間的通信建立是通過 Connection 類來建立,通過傳入客戶端與服務端的 Channel ,即 ChannelClient 與 ChannelServer 來實體化連接,
interface Connection<TContext> extends Client<TContext> {
readonly channelServer: ChannelServer<TContext>;
readonly channelClient: ChannelClient;
}
它們之間的區別是,由于服務端可以同時對多個客戶端服務,因此支持多個 Channel 的獲取,而ChannelClient 為一對一連接,
綜上,我們就梳理清楚了 VSCode 中 IPC 模塊的基本架構,了解了行程間的通信細節,
用一張圖總結梳理一下知識點:

由于 VSCode 的 IPC 模塊天然支持異步能力,因此事實上它并不區分行程是本地行程還是遠端行程,只要是通過 Channel 通信的,都可以被認為是行程間通信,都可以復用相同的代碼撰寫,
參考
VSCode 的官方檔案
VSCode API
VSCode 原始碼解讀--IPC 通信機制
vscode 原始碼決議 - 行程間呼叫
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/518768.html
標籤:JavaScript
