在web端開發(fā)遇到監(jiān)控、聊天、消息提示等場景的時(shí)候,通常會(huì)有需要服務(wù)器主動(dòng)推送消息給前端,前端根據(jù)相關(guān)的信息變更頁面顯示的效果等。一般常用的有三種模式,分別是定時(shí)請求、消息請求監(jiān)聽(我自己定義的名稱)、websocket。
定時(shí)請求和消息請求監(jiān)聽其實(shí)本質(zhì)上都是使用http(s)請求。
定時(shí)請求的話一般都是頁面上設(shè)置setInterval或者setTimeout兩種再加上一個(gè)定時(shí)的時(shí)間,在固定時(shí)間去請求后端,就相當(dāng)于定時(shí)輪詢。
setInterval和setTimeout這兩種方式對于后端技術(shù)的的要求低,不需要后端另外搭建服務(wù)或者其他的消息機(jī)制,只需要不斷地去重復(fù)調(diào)用現(xiàn)有的接口。但是缺點(diǎn)也很明顯,實(shí)時(shí)性過低,在不考慮請求傳輸和后端反應(yīng)時(shí)間的情況下,設(shè)置的時(shí)間就是最大的數(shù)據(jù)延遲時(shí)間,如果將這個(gè)時(shí)間設(shè)置很短的話,短時(shí)間內(nèi),后端和前端都需要較多的請求數(shù)據(jù),那對于前端和后端的壓力也是很大。
同時(shí)因?yàn)閭鬏數(shù)木W(wǎng)絡(luò)狀況、后端的反應(yīng)時(shí)間等實(shí)際情況永遠(yuǎn)不可能為0、后端的并發(fā),前端數(shù)據(jù)的處理等一系列的情況都需要去考慮到。在使用setInterval且配置時(shí)間過短的情況下,經(jīng)常會(huì)出現(xiàn)前一個(gè)請求還沒返回,后一個(gè)的請求都已經(jīng)返回了,就會(huì)頁面上處理的數(shù)據(jù)并非按照實(shí)際的時(shí)間進(jìn)行處理展示的情況。此時(shí)使用setTimeout的話,雖然解決了請求順序的問題,但是遇到請求時(shí)間較長的情況,實(shí)時(shí)性還是有延遲,延遲時(shí)間大概就是設(shè)置的timeout時(shí)間加上http(s)請求的時(shí)間,對于后端相應(yīng)返回的時(shí)間的要求比較高。
另外,在使用這種方式的時(shí)候,前端的開發(fā)人員一定要在頁面銷毀的時(shí)候去取消掉設(shè)置的定時(shí)或者請求,否則定時(shí)請求會(huì)一直保留。


消息請求監(jiān)聽的話比較適用于服務(wù)器單向通知前端,實(shí)質(zhì)上跟第一種是一樣的道理,不同的地方是,它這種方式是直接與后端建立一個(gè)請求,后端會(huì)將這個(gè)請求保持住,一旦有數(shù)據(jù)的時(shí)候,后端會(huì)將相關(guān)的數(shù)據(jù)通過這個(gè)請求返回給前端,前端在得到返回后會(huì)去處理數(shù)據(jù)并且再次重新建立一個(gè)消息請求,重新開始這個(gè)循環(huán)。
考慮到請求超時(shí)等配置,一般這個(gè)請求都是會(huì)在一定時(shí)間返回,讓前端結(jié)束這次的消息監(jiān)聽,重新開始一個(gè)新的消息監(jiān)聽。
在實(shí)際情況中經(jīng)常會(huì)出現(xiàn)在后端返回?cái)?shù)據(jù)前端還沒有處理完并建立新的消息監(jiān)聽請求時(shí)有新消息的情況,如果處理不好這種情況就容易出現(xiàn)消息丟失,或者消息和頁面對不上的情況,這種情況的解決方案是消息打包,后端將比如一段時(shí)間內(nèi)的消息打個(gè)包,在滿足的時(shí)候再返回。
在此方式過程中,如果傳輸?shù)臄?shù)據(jù)包的時(shí)候,如果數(shù)據(jù)包過大,會(huì)造成連接請求的時(shí)間過長,影響監(jiān)聽的實(shí)時(shí)性,便可以考慮在消息打包的時(shí)候,生成一個(gè)類似于id之類的唯一編碼,在消息監(jiān)聽返回的時(shí)候直接將這個(gè)編碼拋給前端,前端接到編碼后,立即重新建立一個(gè)新的消息監(jiān)聽,同時(shí)通過一個(gè)新的接口用監(jiān)聽返回的編碼去向后端請求相關(guān)的數(shù)據(jù),這樣的話,消息監(jiān)聽的服務(wù)和消息返回的服務(wù)可以分開來,消息提示和消息內(nèi)容相互獨(dú)立,不光解決了數(shù)據(jù)接收的實(shí)時(shí)性,同時(shí)對于前端需要提示(類似于某個(gè)地方出現(xiàn)小紅點(diǎn)之類的),但是不要立刻知道需要提示內(nèi)容等情況的話可能效果更好。
建議在后端能力滿足的情況下,使用這套方案。從實(shí)踐而言,這套方案的話,哪怕去后端去拿數(shù)據(jù),返回也很快的,因?yàn)椴煌诙〞r(shí)請求請求,主要的還是從消息存儲(chǔ)中去拿,返回的速度完全是架構(gòu)的問題,再加上這套方案的實(shí)時(shí)性很好,故此推薦。
使用此方式的情況下,如果前端需要與后端進(jìn)行數(shù)據(jù)交換,可以直接使用正常的http(s)請求即可。

websocket的話,似乎是最佳解決方案,但是相比較而言,它在某些方面優(yōu)先不足,比如瀏覽器版本(當(dāng)然,現(xiàn)在這個(gè)幾乎可以忽略不計(jì))、瀏覽器是否禁用JavaScript、token認(rèn)證、服務(wù)器、多端兼容等方面的問題。當(dāng)然,以上這些問題在很多小的,或者要求不是那么高的項(xiàng)目中基本不用考慮,只要不考慮這些問題,websocket幾乎就是最優(yōu)的方案:實(shí)時(shí)性很好,消息容量也能滿足幾乎所有的場景……反正幾乎都是優(yōu)點(diǎn),只是在一些很古老的項(xiàng)目,例如還需要兼容ie的(不知道這些項(xiàng)目還留著干嘛),確實(shí)需要還是要考慮兼容的,一般用戶誰沒事去禁用JavaScript,token啥的換一套檢驗(yàn)方式就得了,服務(wù)器啥的,也不是啥問題,現(xiàn)在一套websocket服務(wù),很輕的。
以上就是一般常用的三種方式,但從技術(shù)上而言,第一種最簡單。如果不考慮技術(shù)的話,建議優(yōu)先websocket,消息請求監(jiān)聽,最后才是定時(shí)請求。