在上一篇中,我們一起分析了 VS Code 整體的代碼架構(gòu),了解了 VS Code 是由前后端分離的方式開(kāi)發(fā)的。且無(wú)論前端是基于 electron 還是 web,后端是本地還是云端,其調(diào)用方式并無(wú)不同。
成都創(chuàng)新互聯(lián)服務(wù)項(xiàng)目包括昆玉網(wǎng)站建設(shè)、昆玉網(wǎng)站制作、昆玉網(wǎng)頁(yè)制作以及昆玉網(wǎng)絡(luò)營(yíng)銷(xiāo)策劃等。多年來(lái),我們專(zhuān)注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,昆玉網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶(hù)以成都為中心已經(jīng)輻射到昆玉省份的部分城市,未來(lái)相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶(hù)的支持與信任!
這樣的架構(gòu)下,前后端的通信方式是如何實(shí)現(xiàn)的呢?本篇我們將一起來(lái)探究 VS Code For Web 的進(jìn)程間通信方式。
對(duì)于多進(jìn)程架構(gòu)的項(xiàng)目,進(jìn)程之間的通信會(huì)通過(guò)進(jìn)程間調(diào)用 (Inter Process Calling, IPC)。VSCode 中自己設(shè)計(jì)了專(zhuān)門(mén)的 IPC 模塊來(lái)實(shí)現(xiàn)通信。代碼位于 src/vs/base/parts/ipc。
export const enum RequestType {
Promise = 100,
PromiseCancel = 101,
EventListen = 102,
EventDispose = 103
}
從 enum type 可以看出,VSCode 的 IPC 模塊同時(shí)支持兩種調(diào)用方式,一種是基于 Promise 的調(diào)用實(shí)現(xiàn), 另一種是通過(guò) Event Emitter/Listener 的那一套事件監(jiān)聽(tīng)機(jī)制來(lái)實(shí)現(xiàn)。
以事件監(jiān)聽(tīng)機(jī)制為例,VSCode 中采用 vscode-jsonrpc
這個(gè)包來(lái)封裝實(shí)現(xiàn),調(diào)用方式如下:
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('testNotification');
connection.listen();
connection.sendNotification(notification, 'Hello World');
服務(wù)端調(diào)用也采用類(lèi)似的包裝:
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('testNotification');
connection.onNotification(notification, (param: string) => {
console.log(param); // This prints Hello World
});
connection.listen();
為了實(shí)現(xiàn)客戶(hù)端與服務(wù)端之間的點(diǎn)對(duì)點(diǎn)通信,我們需要一個(gè)最小單元來(lái)實(shí)現(xiàn)消息的調(diào)用與監(jiān)聽(tīng)。在 VSCode 中,這個(gè)最小單元即為 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(command: string, arg?: any, cancellationToken?: CancellationToken): Promise;
listen(event: string, arg?: any): Event;
}
每次通信過(guò)程,需要客戶(hù)端與服務(wù)端處于同一個(gè) Channel
中。
在 VSCode 中,客戶(hù)端與服務(wù)端之間的通信建立是通過(guò) Connection
類(lèi)來(lái)建立,通過(guò)傳入客戶(hù)端與服務(wù)端的 Channel
,即 ChannelClient
與 ChannelServer
來(lái)實(shí)例化連接。
interface Connection extends Client {
readonly channelServer: ChannelServer;
readonly channelClient: ChannelClient;
}
它們之間的區(qū)別是,由于服務(wù)端可以同時(shí)對(duì)多個(gè)客戶(hù)端服務(wù),因此支持多個(gè) Channel
的獲取,而ChannelClient
為一對(duì)一連接。
綜上,我們就梳理清楚了 VSCode 中 IPC 模塊的基本架構(gòu),了解了進(jìn)程間的通信細(xì)節(jié)。
用一張圖總結(jié)梳理一下知識(shí)點(diǎn):
由于 VSCode 的 IPC 模塊天然支持異步能力,因此事實(shí)上它并不區(qū)分進(jìn)程是本地進(jìn)程還是遠(yuǎn)端進(jìn)程,只要是通過(guò) Channel
通信的,都可以被認(rèn)為是進(jìn)程間通信,都可以復(fù)用相同的代碼編寫(xiě)。
VSCode 的官方文檔
VSCode API
VSCode 源碼解讀--IPC 通信機(jī)制
vscode 源碼解析 - 進(jìn)程間調(diào)用