在上一篇中,咱们一起剖析了 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 ,即 ChannelClientChannelServer 来实例化连贯。

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 源码解析 - 过程间调用