解決 Long Polling Comet 會持續顯示讀取中的問題

此篇文章最近更新時間為2011-06-22 07:54:21 目前共有7篇留言

關於作者 - JosephJ

任職於 Faria。喜好戶外運動、2008 年 5 月完成「跑步環島」。對於新技術跟程式碼有著強烈的偏執狂。

持續顯示的狀態

使用 nodeJS 達成 Long Polling 的效果已經完成了一陣子(請參考 Browser 與 Server 持續同步的作法介紹),
但是有個問題一直被我們的 QA 拿出來唸,就是在 Tab 上及 window.status 的讀取狀態有時會一直顯示著範例連結):

原本會一直有讀取的狀態

對程式開發人員來說,這樣的問題沒什麼大不了,畢竟 Request 本來就尚未中斷,顯示也沒有不對
但對一般使用者來說則顯得相當不專業,感覺有什麼圖片一直無法讀取到
另外也懷疑許多其他的 Bug 是因此產生。

只有 Firefox 有此問題

同事都說他們實作 Long polling 時都沒碰到這樣的問題
我就覺得超級奇怪的,大家的作法應該都是一樣的啊:透過 YUI 的 JSONPRequest 去呼叫 nodeJS...
就拿出當時實作的範例來測(就是上面圖片的那一頁),才發現 IE 或 Chrome 都沒有此問題
因我主要是拿 Firefox 開發、其他兩位是拿 Chrome 來開發才會有此不同的認知。

參考其他網站的作法

雖然只有 Firefox 有這個問題,但還是得解...
就去看了 Plurk 及 Facebook 這兩個有即時更新的網站
發現這兩個網站即使在 Firefox 下也都沒有我碰到的問題...
有挖 Source Code 的必要性啦 ~~

1. Plurk 的作法

其實我記得很久以前噗浪也有跟我一樣的問題(有人有印象嗎?)
當時反而覺得能看到等待的狀態是件很屌的事、因為能實作 Comet 的網站很少啊 ...
發現噗浪是利用相同網域的 Iframe 去做 Long Polling

plurk-solution

我沒有去測試這樣是否能解決我的問題,因為沙盤推演了一下...
我沒辦法弄一個相同網域的 Iframe,所以必定得用 HTML5 postMessage() 的方法來溝通...
實作上對我較為複雜,所以就先擺在一邊。

2. Facebook 的作法

Okay,當下覺得 Plurk 的作法可能就是我要的了,多看一下 Facebook 的來做確認吧!
咦咦咦!Facebook 的作法居然跟我一樣、沒有用 Iframe,只是多了 async="" 的這個屬性?

facebook-solution

async 若有設定的意義為:「執行不遵守 Request 時的順序」,
看來好像跟我的問題有關連性,但是實作之後並沒有發生任何事情 :p

最終解法!

哇!卡關了,我不太想實作噗浪的方法。
只能求助 Google、找到了 StackOverflow 的一篇文章:
How to prevent my browser from showing “waiting for MyHostName” message during ajax Post/Get operation?
它的解法是在 window 的 load 事件後執行 Long Polling 的第一個 Request 即可避免
我嘗試了使用 YUI 的 DOMReady,一樣運作順利啊 :D

在 DOMReady 後跑就解決了

結語

對於噗浪為什麼要在 iframe 做我還是蠻好奇的,有機會再來研究研究。
另外我們先前有此問題時,發現它會暫停掉其他的 Request 直到 long-polling 中斷才發出去
如今解決了狀態顯示的問題,不確定是否有相依性,得再來觀察觀察。
對於 Long Polling 我真的還是小學生啊 :p



Comments

  1. flashman 2011-07-20 10:53:57
    前陣子一整個忙到不行.. @_@"

    這樣啊.. 拿我慢點實做看看... 謝謝啊
  2. ShiningRay 2011-06-27 22:44:50
    放iframe里面,可以让ie也不出现loading
  3. josephj 2011-06-24 08:05:31
    flashman,

    以噗浪或臉書的新訊息通知為例,它的更新相當的即時
    如果 A 寫了一個新訊息、我們的實作方式是寫入資料庫
    而朋友 B - Z 不斷地去詢問資料庫,那資料庫很快就會倒了

    但如果換個方式實作,實作方式不寫入資料庫而是寫入 Redis 這樣的 noSQL 做排程
    就等於有個相當快的緩存機制(通常是用 RAM)
    可以每 5 秒將排程的資料取出處理(例如一個不會中止執行的 Shell Script)
    此時可以將資料批次寫入資料庫、比較節省 I/O
    另外則可檢查好友 B-Z 是否在線上(例如用 memcache key value 對應)
    有的話就想辦法去觸發 nodeJS(例如用 cURL 去戳)
    最後使用者收到回傳的資料

    所以線上的使用者並不會去戳資料庫、而是純粹的等待

    作法有很多種,但是我還是這類功能實作上的新手
    能想到的作法也有限,希望對你有幫助
  4. flashman 2011-06-24 00:14:30
    Queue? 還是有些模糊.

    如果在這一分鐘內有新的資料存進資料庫, 難道說存進的同時也放進Queue?

    謝謝.
  5. josephj 2011-06-23 08:12:17
    flashman,

    通常 Long Polling 是用來解決 Web Server 連線的問題
    所以得搭配 nodeJS 這類可容許 Persist Connection 的方式一起服用

    資料查詢就是另一件事情了
    像 nodeJS 是 Event-driven 的程式(當... 時才處理)
    若利用 while do loop, 也就是 setInterval 來做, 不免喪失它的本意
    Plurk 或 Facebook 流量如此大,不太可能一直去查詢 DB
    我們的作法是利用 Redis 或 Amazon Message Queue 的方案排 Queue (先進先出)
    然後再出來處理的過程中分流去觸發 nodeJS,資料一旦返回 Long Polling 就停止
  6. flashman 2011-06-22 22:08:39
    Long pooling 不會造成mySQL 當掉嗎? 因為用while do loop 一直向mySQL 查詢是否有新資料啊.. 還是說我的想法錯誤?
  7. Caesar 2011-06-22 21:27:31
    我也想清楚的知道long polling 還有什麼秘密!
暱稱: 必填。
Email: 非必填。若填寫為不公開欄位,僅供站長參考聯繫。
內容: 必填。限 255 個字元以內。
驗證碼:
送出

Facebook Comment