解決Socket.IO在IE8下觸發disconnect時間過長


本文地址: http://www.cnblogs.com/blackmanba/p/solve-socketIO-IE8-emit-disconnect-too-long.html或者http://forkme.info/solve-socketIO-IE8-emit-disconnect-too-long/, 轉載請注明源地址。

概述

Node.js是一個是一個構建在Chrome's JavaScript runtime上的應用程序。能夠容易的建立起快速, 可擴展性的應用。Node.js采用事件驅動, 無阻塞I/O模型來保證其輕量性和有效性。對於Javascript語言來說, Node.js的出現具有相當重要的意義。它意味着Javascript不再是傳統意義上只能用於前端開發的語言, Javascript同時也能用於WEB后端程序的開發。Node.js相當於一座橋梁, 通過它可以打通前端與后端開發, 現在通過使用Javascript就能實現功能完備的網站。

在使用Node.js開發聊天模塊的過程中, 采用Socket.IO實現聊天功能。Socket.IO是一個開源的庫, 根據瀏覽器的兼容性不同采用不同的實現方式, 分別支持WebSocket, Adobe Flash Socket, AJAX long polling, AJAX multipart streaming, Forever Iframe以及JSONP Polling這些API。Socket.IO能兼容大部分的瀏覽器, 這也是它的最大優勢。在使用Socket.IO實現聊天模塊的過程中發現一個問題: 在IE8瀏覽器下聊天窗口關閉一分鍾時才觸發服務端的disconnect事件。這讓聊天應用的實時性大打折扣。

原因

為什么IE8下會出現這個問題呢? 通過查詢官方文檔和日志輸出, 發現是以下原因導致: IE8及以下瀏覽器不支持WebSocket協議, 在IE8瀏覽器中, Socket.IO是通過xhr-polling來實現數據傳輸的。服務器一分鍾才會向客服端發送請求來確認client端是否斷開連接。如此一來就會導致觸發服務器disconnect事件的時間過長, 導致實時應用較晚響應, 影響用戶體驗。

解決方法

關於這個問題有以下三種不同的方法解決:

1. 使用flashsocket實現

這是最簡單的一種實現方式, 通過使用flashsocket可以在用戶關閉窗口時觸發disconnect事件通知服務器進行相應的處理。以下是在Socket.IO服務器端的具體配置:

io.set('transports', [
    'websocket',
    'flashsocket',
    'htmlfile',
    'xhr-polling',
    'jsonp-polling'
]);

使用這種方式的優點是實現簡單。缺點如下:

  • 蘋果系統不支持Flash
  • swf文件下載會有一定時間的延時。經過測試在IE8下加載時間大概是10s, 這會嚴重影響體驗。

2. 配置Socket.IO通知時間

根據官方配置, Socket.IO默認是60s發送請求確認客服端是否斷開連接。這是導致觸發disconnect事件過慢的原因,可以將相關的時間縮短, 讓服務端更快的發送請求。配置代碼如下:

io.configure('production', function() {
    io.set('heartbeat timeout', 2);
    io.set('heartbeat interval', 1);
    io.set('close timeout', 5);
    io.set('polling duration', 3);
});

io.configure('development', function() {
    io.set('heartbeat timeout', 2);
    io.set('heartbeat interval', 1);
    io.set('close timeout', 5);
    io.set('polling duration', 3);
});

以上分別是生產環境和開發環境的配置, 各個參數的意義詳見官方配置。通過配置, IE8觸發disconnect的時間變為5s, 在一定程度上增強了實時性, 缺點如下:

  • 只是接近實時, 實際上還是要經過幾秒的時間才會觸發事件
  • 服務端發送確認請求的次數增加, 會占用更多的帶寬以及更多消耗服務器的性能

3. 調用disconnect方法主動通知服務端

以WEB在線聊天為例。通過監聽瀏覽器的onBeforeunload事件, 在窗口關閉前發送請求通知服務器並調用disconnect()方法主動關閉連接。實現代碼如下:

// 使用jquery庫監聽瀏覽器的onBeforeunload事件
$(window).bind('beforeunload', function (e) {

	// 通知瀏覽器關閉連接
	socket.disconnect();

	/**
	 *  如果用戶選擇不關閉瀏覽器, 就要進行Socket的重新連接
	 *  第一個setTimeout的作用是將第二個setTimeout放置於執行隊列中, 接下來執行return
	 *  阻塞了第二個setTimeout執行。確認關閉窗口時, 瀏覽器關閉不會執行第二個setTimeout,
	 *  取消關閉, 第二個setTimeout將會在1s后執行
	 **/
	setTimeout(function () {
        setTimeout(function () {
            socket.socket.reconnect();
        }, 1000);
    }, 1);

	// 返回字符串, 讓用戶確認是否關閉頁面
	return "是否關閉窗口";
}	

這種方式的最大好處就是在IE8下可以做到"實時"通知服務端關閉連接, 只取決於網絡的快慢。當然缺點是實現有些復雜。

總結

新的協議如websocket的使用讓開發變得更加簡單。但在舊的瀏覽器上並沒有這些新的協議。使用Socket.IO, 通過其內部的自動切換, 可以用同一套API兼容不同的瀏覽器。但不同底層實現方式的差別仍然存在。讓低版本的瀏覽器兼容是我們在開發過程中必須考慮的問題。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM