5

Windows と Workers の間の RPC スタイルの通信チャネルのために、TypeScript 言語機能を利用した優れた一般的な設計とは?

SharedWorkersは、特定のブラウザー ウィンドウのコンテキスト外でブラウザーによって実行される JavaScript コード リストです。単一の SharedWorker (スクリプト URI による) は、開いているすべてのブラウザー ウィンドウで共有され、独自のコードがそれを要求します。worker.portWindows とワーカーは、送信者が postMessage() でき、受信者が「メッセージ」イベントをリッスンできるエンタングル オブジェクトを介して通信します。投稿が許可されている最も一貫してサポートされているタイプは、string簡単に作成できる単一のタイプJSON.stringify(ofSomeObject)ですが、任意のカスタム形式にすることができます。

TypeScriptは JavaScript の拡張機能であり、便利な型安全性やその他の便利なアプリケーション コード管理機能を提供します。

WCF などのリモート プロシージャ コールライブラリは、通信チャネルの両側 (すべて) で共有される SOA スタイルの契約インターフェイスを使用し、単調でエラーが発生しやすい要求のシリアル化と逆シリアル化の必要性を抽象化します。


ブラウザー Windows とそのワーカーの間の通信は、チャネルを介してコードをデータとして渡すことができないため、RPC に似ています。主な違いの 1 つは、通信が一方向のみであることです。送信者はメッセージを投稿できますが、ブロックして結果を待つことはできません。代わりに、アプリケーション層は、受信したデータと送信された要求を照合する役割を果たします (該当する場合)。

TypeScript の型付け機能を利用するには、コントラクト パラダイムに従うのが適切な選択のように思えます。必要なもの:

  1. 受信者のサービス コントラクトごとに 1 つのインターフェイス。
  2. 各コントラクトのレシーバ実装
  3. 各コントラクトのプロキシ実装

まず、lib.d.ts 定義に基づく SharedWorkers の構築について TypeScript に教える必要があります。SharedWorker.d.ts:

interface ConnectEvent extends Event {
    ports: MessagePort[];
};

interface SharedWorker extends EventTarget, AbstractWorker {
    port: MessagePort;
};

declare var SharedWorker: {
    prototype: SharedWorker;
    new (scriptURL: any, name: any): SharedWorker;
    new (scriptURL: any): SharedWorker;
}

WCF には、接続されたクライアントについて知るためのアンビエント OperationContext があります。また、ほとんどの場合、リクエストへのレスポンスを送信するために値を返します。

JavaScript には ThreadStatic がなく、OperationContext に相当するアンビエントを確実に提供できるとは思えません。(各コード リストはシングル スレッドで実行されますが、非同期がタイマー コールバックで実装され、おそらく Worker 実装で使用される方法は、正しく追跡できるとは思いません。)

MessagePorts では、値を返すことはできません。代わりに、リクエスターに別の一方向応答を送信する必要があるため、返される MessagePort へのハンドルが必要です。ただし、この戻り MessagePort は、Proxy 実装では必要ないため、Contact の一部にすることはできません。私が考えることができるのは、戻り MessagePort や、ブロードキャスト メッセージ用に接続されたすべての MessagePorts の配列などのその他のデータなど、レシーバー/プロキシ固有の違いで初期化された実装クラスの新しいインスタンスを作成することだけです。その後、実装のメンバー メソッドは、OperationContext のようにそれらを参照できます。

メッセージ イベント ハンドラの例:

worker.port.addEventListener('message', (e: MessageEvent) => {
    var data = JSON.parse(e.data);
    new ReceiverImplementation(worker.port)[data.name].apply(this, data.params);
}, false);

プロキシ実装には、次のような機能がある場合があります。

SessionLogin(username: string) {
    this.worker.port.postMessage(Command('SessionLogin', arguments));
}

メッセージ イベント ハンドラーは、受信したパラメーターを指定されたメソッド名に適用します。メソッド名の衝突を避けたいので、ReceiverImplementation オブジェクトはおそらく他のクラスから独立している必要があります。おそらくそうではありませんが、クライアント マシン上で実行されるクライアント コードの間で話しているのです。同じセキュリティ上の懸念はありません (ガードを強制する機能もありません)。

プロトタイプ全体を投稿するのは長すぎたり複雑すぎたりするため、主題が原因で jsfiddle に収まりません。とにかく、私が持っているものはそれほど素晴らしいものではありません。これはまだ、ごくわずかな機能のための一連のボイラープレート コードのように見えます。

そして、これらすべてが共有されていない Web ワーカーにも当てはまると確信していますが、このようにコミュニケーションに問題があるため、共有されていない種類の価値提案は見当たりません!

これは広大な質問ですが、うまく説明できたことを願っています。この Window-Worker コミュニケーションを解決するためのアイデアは何ですか? JavaScript のリラックスした性質と、TypeScript の単なる安全性の錯覚を利用して、よりシンプルでエラーの少ないコミュニケーションを実現するにはどうすればよいでしょうか? 私は、.NET の制限にインスパイアされた WCF を JavaScript に移植しすぎているのではないかと考えています。

ありがとう。

4

0 に答える 0