根據規格書的解釋,channel messaging與cross-document messaging的差別在於,他提供了一個全雙工的溝通管道,所以理論上不同的網頁可以同時寫入/讀出訊息。不過我一時想不出方法怎樣來測試這個「全雙工」...所以還是簡單測試一下吧。
Channel Messaging會使用到好幾個物件來協作,包括MessagePortArray, MessagePort以及MessageChannel。每個MessageChannel裡面有兩個MessagePort,就像管線的兩端,兩個要溝通的文件各使用一端,就可以互相溝通。
MessagePortArray是一個裡面只包含MessagePort物件的陣列。MessagePort有start()、close()以及postMessage(),每個port需要先start(),才能使用postMessage傳送訊息。接收訊息則需要使用MessagePort的onmessage事件,用非同步的方式來讓事件處理函數處理。MessageChannel在使用時必須先用new MessageChannel()產生實例,他的構成很簡單,就是兩個MessagePort,分別名為port1及port2。
在使用上通需要額外透過cross document messaging的postMessage(),把另外一個MessagePort傳遞給另外一端,這個postMessage()第三個參數必須是一個MessagePortArray,所以需要的話,可以new好幾個MessageChannel,然後用陣列同時傳幾個MessagePort給對方。
下面的範例程式其實跟昨天試用cross document message的測試程式差不多,只是訊息改成用MessagePort傳遞,而cross document message只用來傳送MessagePortArray:
...耶,長度又超過限制,我放上plurk paste好了,語法highlight比較漂亮:
http://paste.plurk.com/show/323246/
iframe中使用的test632a.html如下:
<html lang="zh-TW">
<meta http-equiv="Content-Type" content="text/html; charset=utf8">
<style>
div {
border: solid 2px #336699;
margin: 10px;
padding: 5px;
border-radius: 5px;
vertical-align: top;
text-align: center;
display: inline-block;
}
#container {
background: #88BBFF;
width: 480px;
}
.panel {
background: #99CCFF;
border: dotted 1px #4477AA;
width: 90%;
margin: 0px;
text-align: left;
font-size: 12px;
}
</style>
<div id="container">Received messages.<div id="panel1" class="panel"></div><div id="panel2" class="panel"></div>
<script>
try {
window.addEventListener('message', function(e) {
var port1 = null;
var port2 = null;
if(e.data == 'hello' && e.ports.length > 0) {
port1 = e.ports[0];
}
port1.start();
port1.addEventListener('message', function(e) {
var str = '<li>';
str += '[' + e.origin + ']';
str += '[' + e.ports + ']';
str += ' : ';
str += e.data;
str += '</li>\n';
document.getElementById('panel1').innerHTML += str;
port1.postMessage('got it at '+(new Date())+'.');
if(e.ports) {
port2 = e.ports[0];
port2.start();
port2.addEventListener('message', function(e) {
var str = '<li>';
str += '[' + e.origin + ']';
str += '[' + e.ports + ']';
str += ' : ';
str += e.data;
str += '</li>\n';
document.getElementById('panel2').innerHTML += str;
port2.postMessage('got it at '+(new Date())+'.');
}, false);
}
}, false);
}, false);
}catch(e){alert(e);};
</script>
程式中首先用postMessage()傳了一個MessagePort到test632a.html,接下來透過第一次使用MessagePort.postMessage(msg, MessagePortArray)的第二個參數再傳了一個MessagePort到test632a.html,接下來就使用兩個channel來傳送同樣訊息,但是各自顯示在兩個block上。執行結果像這樣:
測試過程中發現最大的問題是...目前只有Opera瀏覽器正確無誤地支援Channel Messaging,Chrome7雖然可以使用MessageChannel,但是用postMessage傳送port到另一個文件時會出現錯誤,所以等於沒支援。