使用AJAX和WebSocket都可以實現(xiàn)消息推送,但它們在實現(xiàn)方式和適用場景上有所不同。下面是使用這兩種技術實現(xiàn)消息推送的簡要說明。
AJax實現(xiàn)或WebSocket實現(xiàn)對比 AJAX 實現(xiàn)消息推送 AJAX(Asynchronous JavaScript and XML)允許你在不重新加載整個頁面的情況下,與服務器進行數(shù)據(jù)交換。但是,傳統(tǒng)的AJAX并不直接支持實時消息推送,因為它基于請求-響應模式。為了模擬消息推送,你可以使用輪詢(polling)或長輪詢(long-polling)技術。
輪詢(Polling) 輪詢是定期向服務器發(fā)送請求,以檢查是否有新的消息。這種方法簡單但效率較低,因為即使在沒有新消息的情況下,也會頻繁地發(fā)送請求。
function pollForMessages ( ) { $.ajax({ url : '/messages' , // 假設這是獲取消息的API端點 method : 'GET' , success : function (data ) { // 處理接收到的消息 console .log(data); // 等待一段時間后再次輪詢 setTimeout(pollForMessages, 5000 ); // 每5秒輪詢一次 }, error : function ( ) { // 處理請求失敗的情況 setTimeout(pollForMessages, 10000 ); // 等待更長時間后重試 } }); }// 開始輪詢 pollForMessages();
長輪詢(Long-Polling) 長輪詢是輪詢的一種改進方式??蛻舳税l(fā)起一個請求到服務器,服務器會保持這個連接打開直到有新消息到達或超時,然后返回新消息或超時響應。這種方式比簡單輪詢減少了無效的請求,但仍然存在一定的延遲和資源浪費。
使用長輪詢時,通常需要在服務器端有特殊的支持來保持連接直到有數(shù)據(jù)可以發(fā)送。
WebSocket 實現(xiàn)消息推送 WebSocket 提供了一個全雙工的通信通道,允許服務器主動向客戶端推送消息。一旦建立了WebSocket連接,服務器和客戶端就可以隨時向對方發(fā)送消息,而不需要像AJAX那樣頻繁地發(fā)起請求。
WebSocket 客戶端實現(xiàn) var socket = new WebSocket('ws://your-server-url' ); socket.onopen = function (event ) { // 連接打開后,你可以向服務器發(fā)送消息 socket.send('Hello Server!' ); }; socket.onmessage = function (event ) { // 當收到服務器發(fā)來的消息時,觸發(fā)此事件 console .log('Received:' , event.data); }; socket.onerror = function (error ) { // 處理錯誤 console .error('WebSocket Error:' , error); }; socket.onclose = function (event ) { // 連接關閉時觸發(fā) console .log('WebSocket is closed now.' ); };
WebSocket 服務器端實現(xiàn) 服務器端實現(xiàn)WebSocket通常依賴于特定的服務器軟件或框架,如Node.js的ws
庫、Java的Spring WebSocket等。這些庫或框架提供了處理WebSocket連接的API,你可以在這些連接上發(fā)送和接收消息。
在WebSocket服務器端,你可以保存與每個客戶端的連接,并在需要時向它們發(fā)送消息
下面開始做封裝WebSocket的介紹
想象 想象一下,你是一位超級快遞員,負責把客戶的包裹準確無誤地送到指定的地址。這些包裹里裝的是WebSocket消息,而你的任務是根據(jù)每個包裹上的userid
和url
信息,找到正確的收件人并將包裹送達。
首先,你需要準備一輛超級快遞車(也就是WebSocket連接)。這輛車非常智能,它可以記住多個收件人的地址(url
),并且同時為他們運送包裹。但是,每個收件人(userid
)只能對應一個地址,這樣才不會送錯。
當有客戶找你寄送包裹時,他們會告訴你收件人的userid
和地址url
。你會把這些信息記在小本本上,然后告訴超級快遞車:“嘿,車車,我們要去這個地方送這個包裹給這個人!”
快遞車非常聽話,它會立即啟動并前往指定的地址。一旦到達,它就會靜靜地等待,直到有包裹需要送出。
當你需要發(fā)送消息時,就像把包裹放進快遞車里一樣簡單。你只需告訴快遞車:“給這個userid
的人送這個包裹!”快遞車就會準確無誤地將包裹送達給指定的收件人。
如果收件人回復了消息,快遞車就像個貼心小助手一樣,會第一時間把回信拿給你。你可以輕松地查看并處理這些回信。
這樣一來,你就不再需要親自跑腿送包裹了,超級快遞車會幫你搞定一切。你只需要告訴它去哪里、送給誰,然后坐等好消息就行啦!
WebSocketMessenger(快遞服務公司) :
存儲收件人(recipient
)和地址(address
)信息。 提供發(fā)送消息(send_message
)的方法。 由WebSocketMessenger
創(chuàng)建和管理。 使用WebSocketMessenger
的服務來發(fā)送消息。 在WebSocket連接的另一端,接收來自WebSocketMessenger
傳遞的消息。 這些角色通過WebSocket連接進行交互,實現(xiàn)了消息的發(fā)送和接收。WebSocketMessenger
作為服務提供者,管理著快遞員(WebSocket連接實例),而客戶和收件人則是服務的使用者。
代碼層面 服務node代碼可以看上篇文章: 僅僅只會Ajax,那就out了!WebSocket實戰(zhàn)解鎖實時通信新境界! [1]
// WebSocketMessenger(快遞服務公司) class WebSocketManager { constructor (url = null , userId = null , receiveMessageCallback = null ) { this .socket = null // WebSocket 對象 this .sendTimeObj = null // 發(fā)送信息給服務端的重復調(diào)用的時間定時器 this .reconnectTimeObj = null // 嘗試鏈接的宏觀定時器 this .reconnectTimeDistance = 5000 // 重連間隔,單位:毫秒 this .maxReconnectAttempts = 10 // 最大重連嘗試次數(shù) this .reconnectAttempts = 0 // 當前重連嘗試次數(shù) this .id = userId //用戶ID(業(yè)務邏輯,根據(jù)自己業(yè)務需求調(diào)整) this .url = url // WebSocket 連接地址 this .receiveMessageCallback = receiveMessageCallback // 接收消息回調(diào)函數(shù) } /** * 開啟WebSocket */ async start() { if (this .url && this .id) { // 連接WebSocket this .connectWebSocket() } else { console .error('WebSocket erros: 請傳入連接地址和用戶id' ) } } /** * 創(chuàng)建WebSocket連接, 超級快遞車 */ connectWebSocket() { // 通過id生成唯一值(服務端要求,具體根據(jù)自己業(yè)務去調(diào)整) let id = `${this .id} -${Math .random()} ` // 創(chuàng)建 WebSocket 對象 this .socket = new WebSocket(this .url, id) // 快遞員(WebSocket連接實例 // 處理連接打開事件 this .socket.onopen = (event ) => { // 給服務端發(fā)送第一條反饋信息 this .startSendServe() } // 處理接收到消息事件 this .socket.onmessage = (event ) => { this .receiveMessage(event) } // 處理連接關閉事件 this .socket.onclose = (event ) => { // 清除定時器 clearTimeout(this .sendTimeObj) clearTimeout(this .reconnectTimeObj) // 嘗試重連 if (this .reconnectAttempts < this .maxReconnectAttempts) { this .reconnectAttempts++ console .log('重試鏈接次數(shù):' + this .reconnectAttempts) this .reconnectTimeObj = setTimeout(() => { this .connectWebSocket() }, this .reconnectTimeDistance) } else { // 重置重連次數(shù) this .reconnectAttempts = 0 console .error( 'WebSocketManager erros: Max reconnect attempts reached. Unable to reconnect.' ) } } // 處理 WebSocket 錯誤事件 this .socket.onerror = (event ) => { console .error('WebSocketManager error:' , event) } } /** * 發(fā)送給node的第一條信息 */ startSendServe() { this .sendMessage('hi I come from client' ) } /** * 發(fā)送消息 * @param {String} message 消息內(nèi)容 */ sendMessage(message) { if (this .socket.readyState === WebSocket.OPEN) { this .socket.send(message) } else { console .error( 'WebSocketManager error: WebSocket connection is not open. Unable to send message.' ) } } /** * 接收到消息 */ receiveMessage(event) { // 根據(jù)業(yè)務自行處理 console .log('receiveMessage:' , event.data) this .receiveMessageCallback && this .receiveMessageCallback(event.data) } /** * 關閉連接 */ closeWebSocket() { this .socket.close() // 清除定時器 重置重連次數(shù) clearTimeout(this .sendTimeObj) clearTimeout(this .reconnectTimeObj) this .reconnectAttempts = 0 } }
代碼解讀 該類用于管理和控制WebSocket連接,包括連接建立、消息接收、重連機制等。下面是對代碼的詳細解讀:
構造函數(shù) constructor
userId
: 用戶的ID,用于業(yè)務邏輯處理。receiveMessageCallback
: 接收消息時的回調(diào)函數(shù)。初始化了一些成員變量,包括socket
(WebSocket對象)、定時器對象(sendTimeObj
和reconnectTimeObj
)、重連間隔和嘗試次數(shù)等。 start
方法檢查url
和userId
是否存在,若存在則調(diào)用connectWebSocket
方法建立WebSocket連接。 connectWebSocket
方法生成一個基于用戶ID和隨機數(shù)的唯一值作為WebSocket的子協(xié)議(或協(xié)議片段)。 設置了WebSocket的onopen
、onmessage
、onclose
和onerror
事件處理器。 事件處理器 onopen
: 當WebSocket連接打開時觸發(fā),開始發(fā)送消息給服務端(通過startSendServe
方法,該方法在代碼片段中未給出)。onmessage
: 當接收到服務端發(fā)送的消息時觸發(fā),調(diào)用receiveMessage
方法處理消息。onclose
: 當WebSocket連接關閉時觸發(fā),首先清除相關定時器,然后嘗試重連。如果重連次數(shù)未達到最大限制,則設置定時器在一段時間后重新調(diào)用connectWebSocket
進行重連;如果達到最大重連次數(shù),則重置重連次數(shù)并輸出錯誤信息。onerror
: 當WebSocket發(fā)生錯誤時觸發(fā),輸出錯誤信息。 當服務端斷開后開始重連image.png image.png
receiveMessage
方法該方法應該是用來處理從服務端接收到的消息,具體實現(xiàn)取決于業(yè)務邏輯。根據(jù)傳入的回調(diào)函數(shù)receiveMessageCallback
,可以對接收到的消息進行相應處理 使用Demo index.html
<head > <meta charset ="UTF-8" > <meta http-equiv ="X-UA-Compatible" content ="IE=edge" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > <script src ="./webSocketManager.js" > </script > <script > // const WebSocketManager = require('./webSocketManager.js') console .log(WebSocketManager) /** * 接收消息回調(diào) */ const receiveMessage = (res )=> { console .log('接收消息回調(diào):' ,res) } const socketManager = new WebSocketManager('ws://localhost:3000' , 'userid292992' , receiveMessage) socketManager.start() </script > </head >
導入模塊即可使用
總結: 相對完善的WebSocket管理器,能夠處理連接建立、消息接收和重連等常見場景。但需要注意的是,具體的業(yè)務邏輯和錯誤處理可能需要根據(jù)實際情況進行進一步的完善和優(yōu)化。
該文章在 2024/7/2 10:23:34 編輯過