2012-06-12 78 views
4

我正在構建一個執行大量客戶端數據下載和處理的應用程序。數據處理通過在駐留在子域上的iframe中處理而與主應用程序隔離。這是下載數據的iframe。通信是通過postMessage。在同一個域上的不同窗口之間進行通信

一切工作正常,但它可能會更好。

如果用戶打開額外的選項卡/窗口,應用程序當前會重新加載所有數據,甚至可能會執行重複的處理工作,這不是一個問題,除了會減慢所有操作並減少頁面加載時間。

我想要做的是每個頂級選項卡/窗口只與一個處理iframe進行通信,如果原始窗口關閉,可以恢復。麻煩的是,這些不是通過JavaScript打開,而是通過普通的瀏覽器方法打開標籤中的鏈接,所以我無法獲得發送消息所需的iframe的引用。

是否有反正我可以將iframe的窗口引用傳遞給其他選項卡,以便它們可以通過postMessage與它進行通信?在某種程度上可以通過共享工作人員來實現嗎?

我意識到我可以在整個處理任務中使用共享工作人員,但由於數據來自第三方域,因此無法從工作人員中訪問,所以這會產生問題。

只需要與所有主流瀏覽器的最新版本兼容。

編輯:我剛剛發現SharedWorker尚未在firefox中實現,所以我猜這是行不通的。任何其他方式我可以實現這一目標?

編輯2:我發現,你可以使用:

var win = window.open('', 'my_window_name'); 

捕捉來自任何其他窗口的iframe的參考。但是,如果iframe尚不存在,則它會將其作爲窗口打開。即使它立即關閉,它也會導致閃爍並導致「彈出窗口阻止」消息,使其無法使用。

+0

我想網絡工作者是不是一種選擇,因爲它只會在IE 10中工作;-) –

+0

使用html5 localstorage,可能是? – pahnin

+0

並使用javascript來檢查 – pahnin

回答

2

如果有其他人發現這一點,我想出了一個解決方案。這有點冒險,需要進一步的測試。但到目前爲止它正在工作。如果需要的話,它可以跨域使用。

它使用了兩種技巧的組合。

的第一種是使用

remote_window = window.open("", "remote_window_name"); 

抓取到窗口的引用。這是有效的,因爲如果一個窗口已經以給定名稱打開,那麼返回一個引用而不是打開一個新窗口。

但是,如果iframe不存在,就會彈出一個新窗口。本地存儲用於防止這種情況。當窗口/選項卡加載時,它會檢查localStorage以查看是否有另一個頁面已經具有共享的iframe。如果沒有,則插入iframe,並在本地存儲中設置一個標誌,表示它可用。

作爲最後一個開放的度假村,如果窗口仍然打開,則使用try塊關閉新打開的窗口。 try塊可以防止跨域錯誤。這意味着最糟糕的情況是用戶看到一個窗口彈出並消失,或者他們會看到「啓用彈出窗口」消息。我還沒有設法在測試中觸發這一點 - 這只是一個邊緣案例回落。

try { 
    if(store_window.location.href === "about:blank"){ 
     remote_window.close(); 
     remote_window = insertIfame(); 
    } 
} catch(err) { 
} 

添加了onunload事件,該事件在頁面關閉時刪除標誌。

另外創建一個setInterval,它不斷地刷新超時標誌。我每秒運行4次;當加載第二個窗口/選項卡時,它會在嘗試與之通信之前檢查iframe標誌是否超時。這是一個小開銷,但遠遠低於我第二次iframe加載的成本。如果瀏覽器崩潰或onunload因任何原因未觸發,這將用於防止陳舊的數據。當檢查超時時間時(當前爲1秒),在主窗口卡在一個循環中時,我會包含一個小的餘地。剩餘空間僅限於超時,而不是完全移除標誌的卸載事件。

如果原始窗口與iframe關閉,每次發送消息時都需要檢查標誌。發生這種情況時,iframe會重新插入需要它的第一個打開的窗口,並且標誌被重置。

發回消息很容易。只需使用receiveMessage的event.source屬性 - 這指向發送窗口。

要解釋的最後一個邊緣情況是,如果主窗口關閉,而iframe是輔助窗口的中間進程。理論上這可以通過在iframe中使用onunload事件來處理,以便將消息發送回任何正在處理數據的窗口。但我還沒有實現它,它可能無法完成頁面卸載之前。處理它的另一種方法是通過在檢查標誌和重試的輔助窗口中超時,我可能會去這條路由,因爲消息已經超時了。

相關問題