共有ワーカーとデータのやり取りをするには?
共有ワーカーの接続
バックグラウンドで独立した処理を行うワーカーには、自分自身を起動したコードとのみ通信できる専用ワーカーと、複数のコードと通信可能な共有ワーカーがあります。
共有ワーカーとの接続は、そのワーカーに対するクライアントとなるSharedWorkerオブジェクトをコンストラクター「SharedWorker(url, [name])」を使ってインスタンス化することで行います。
引数urlには、その共有ワーカー上で実行させる処理を記述したファイルのurlを指定します。省略可能な第2引数nameには、その共有ワーカーの名前を指定します。
指定するファイルはセキュリティ上、urlの生成元(オリジン)が起動側と同じものに限定されます。オリジンとは、スキーム(urlの「http://」の部分)、ドメイン(urlの「www.example.com」の部分)、ポート(urlの「:8080」の部分)を合わせたもののことです。
接続先の共有ワーカーは、urlとnameによって区別されます。同じurlの同じファイルを実行する共有ワーカーでも、異なるnameが指定された場合は、別の共有ワーカーとなります。
共有ワーカーは、最初に自分への接続が行われた時点で起動します。
// 共有ワーカーとの接続
// この二つのインスタンスは同じ共有ワーカーに接続する
var worker1 = new SharedWorker('backend.js');
var worker2 = new SharedWorker('backend.js');
// この二つのインスタンスは名前が違うので、別の共有ワーカーに接続する
// worker1とworker2が共通して接続している共有ワーカーとも名前が違うので別になる
var worker3 = new SharedWorker('backend.js','myWorkerA');
var worker4 = new SharedWorker('backend.js','myWorkerB');
urlとnameのセットが同じであれば、別のタブやウィンドウ、オリジンが同じ別のページから接続しても、同じ共有ワーカーへの接続になります。
// 上とは別ファイルのコード
// worker4と同じ共有ワーカーに接続する
var worker5 = new SharedWorker('backend.js','myWorkerB');
データの送受信を仲介するMessagePortオブジェクト
共有ワーカーで、データの送受信を行うには、MessagePortオブジェクトを利用します。このオブジェクトには、専用ワーカーと類似した、以下のメソッドとイベントハンドラが存在します。(MessagePortオブジェクトの詳細についてはチャネルメッセージングを実装するには?を参照ください)
MessagePortオブジェクトは接続元と接続先の二つのインスタンスがペアとなって一つの送受信のチャンネルを表します。
一方の側のMessagePortオブジェクトから「postMessage(message)」メソッドを呼び出すと、ペアになったMessagePortオブジェクトでmessageイベントが発生します。
共有ワーカーとの通信の場合、それぞれの接続について、接続元と接続先のMessagePortオブジェクトが生成され、ペアとして設定されます。
接続元のコードでの、共有ワーカーとのデータ送受信
接続元のコードで、共有ワーカーとデータの送受信を行うには、SharedWorkerオブジェクトのport属性を通じてMessagePortオブジェクトにアクセスします。
// 接続元の側のコード
// 共有ワーカーへの接続を開始
var worker = new SharedWorker('shared.js');
// 共有ワーカーへの接続ポートを取得
var port = worker.port;
// 共有ワーカーからデータを受信した時の処理を定義する
port.onmessage = function(event){
console.log(event.data);
}
// メッセージを共有ワーカーへ送信する
port.postMessage("送信データ");
messageイベントへのハンドラの定義は「addEventListener(event,handler,useCapture)」を使って行うこともできます。
ただし、この場合は、onmessageイベントハンドラに代入する場合と違い、明示的にメッセージの送受信を「start()」メソッドで開始する必要があります。
// 共有ワーカーからのデータ受信時のイベントハンドラを定義する
port.addEventListener('message', function(event){console.log(event.data)}, false);
// データの送受信の開始
port.start();
共有ワーカー上のコードでの、接続元のコードとのデータ送受信
共有ワーカーの側で接続元とデータの送受信を行うには、まず、connectイベントのハンドラである、onconnectイベントハンドラを定義します。
connectイベントは、接続元と接続を開始するごとに発生するイベントで、それぞれの接続元についての初期処理をこのイベントで行います。
なお、共有ワーカー側の環境ではonconnectイベントハンドラは既定のオブジェクトのイベントなので、下記の例のようにグローバル変数のようにして代入します。詳細はワーカー上で動くコードを実装するには?を参照ください。
開始された接続の、共有ワーカー側のMessagePortオブジェクトは、つねにこのイベントハンドラの引数(event)のports属性に格納された配列の最初の位置「event.ports[0]」に格納されています。
この参照を取得して以降の処理は、基本的に接続元での処理と同様です。
以下の例では、受け取ったメッセージをそのまま送り返しています。
// 共有ワーカー上のコード
onconnect = function(event){
// 相手先が接続元に設定されたMessagePortオブジェクトを取得
var port = event.ports[0];
// メッセージ受信時のハンドラを定義
port.onmessage = function(event){
// 受け取ったメッセージを送り返す
port.postMessage(event.data);
}
}
connectイベントはその接続元との初回接続時に発生するイベントです。メッセージの送受信のたびに発生するわけではないことに注意してください。
関連項目
ワーカー上で動くコードを実装するには?