在上一篇中,咱们一起剖析了 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 源码解析 – 过程间调用