前端實(shí)時(shí)通信的8種方式及其優(yōu)缺點(diǎn)和實(shí)現(xiàn)方式
1.短輪詢
短輪詢的原理很簡(jiǎn)單,每隔一段時(shí)間客戶端就發(fā)出一個(gè)請(qǐng)求,去獲取服務(wù)器最新的數(shù)據(jù),一定程度上模擬實(shí)現(xiàn)了即時(shí)通訊。
- 優(yōu)點(diǎn):兼容性強(qiáng),實(shí)現(xiàn)非常簡(jiǎn)單
- 缺點(diǎn):延遲性高,請(qǐng)求中有大半是無(wú)用,非常消耗帶寬和服務(wù)器資源,影響性能
- 應(yīng)用: 二維碼掃碼確認(rèn)、信息通知
- 實(shí)現(xiàn)方式:
借用定時(shí)器實(shí)現(xiàn)短輪詢
created(){ this.shortPolling = setInterval(function(){ that.getRuset() },5000) }, ... getResult(){ var that = this this.$axios('xxx,',post).then(res=>{ if(res.code === 200){//拿到想要的結(jié)果 ... //定時(shí)器是否清除由業(yè)務(wù)場(chǎng)景決定 clearInterval(this.shortPolling) } }) }
2.comet(長(zhǎng)輪詢、長(zhǎng)連接)
comet有兩種主要實(shí)現(xiàn)手段,一種是基于 AJAX 的長(zhǎng)輪詢(long-polling)方式,另一種是基于 Iframe 及 htmlfile 的流(streaming)方式,通常被叫做長(zhǎng)連接。
具體兩種手段的操作方法請(qǐng)移步Comet技術(shù)詳解:基于HTTP長(zhǎng)連接的Web端實(shí)時(shí)通信技術(shù)
2.1、長(zhǎng)輪詢
客戶端向服務(wù)器發(fā)送Ajax請(qǐng)求,服務(wù)器接到請(qǐng)求后hold住連接,直到有新消息才返回響應(yīng)信息并關(guān)閉連接,客戶端處理完響應(yīng)信息后再向服務(wù)器發(fā)送新的請(qǐng)求。
- 優(yōu)點(diǎn):兼容性好,在無(wú)消息的情況下不會(huì)頻繁的請(qǐng)求,資源浪費(fèi)較小
- 缺點(diǎn):服務(wù)器hold連接會(huì)消耗資源,返回?cái)?shù)據(jù)順序無(wú)保證,難于管理維護(hù)
- 應(yīng)用: webQQ、開心網(wǎng)、校內(nèi),Hi網(wǎng)頁(yè)版、Facebook IM等等
- 實(shí)現(xiàn)方式:
主要由后端hold住連接,我們就是正常的發(fā)送請(qǐng)求即可
getResult(){ var that = this this.$axios('xxx,',post).then(res=>{ if(res.code === 200){ ... }else{ this.getResult() } ... }) }
正常來(lái)說(shuō)我們前端會(huì)設(shè)置請(qǐng)求超時(shí)時(shí)間,那么我們就和后端約定,在超時(shí)范圍內(nèi)必須返回結(jié)果在前端即可。
2.2、長(zhǎng)連接
在頁(yè)面里嵌入一個(gè)隱蔵iframe,將這個(gè)隱蔵iframe的src屬性設(shè)為對(duì)一個(gè)長(zhǎng)連接的請(qǐng)求或是采用xhr請(qǐng)求,服務(wù)器端就能源源不斷地往客戶端輸入數(shù)據(jù)。 此方法已經(jīng)過(guò)時(shí),我推薦使用,畢竟現(xiàn)在都已經(jīng)放棄iframe
- 優(yōu)點(diǎn):兼容性好,消息即時(shí)到達(dá),不發(fā)無(wú)用請(qǐng)求
- 缺點(diǎn):服務(wù)器維護(hù)長(zhǎng)連接消耗資源
- 實(shí)例:Gmail聊天
- 實(shí)現(xiàn)方式:
//在vue中嵌入iframe <iframe ref="iframe" v-show="iframeShow"></iframe> watchIframe(){ //先找到iframe的窗口 this.iframeWin = this.$refs.iframe.contentWindow; //向iframe發(fā)送信息,大括號(hào)內(nèi)是發(fā)送的內(nèi)容; this.iframeWin.postMessage( { },"*" ); //怎樣監(jiān)聽(tīng)iframe傳過(guò)來(lái)的信息 window.addEventListener("message", this.handleMessage); //獲取iframe傳過(guò)來(lái)的信息 handleMessage(res){ //res為傳過(guò)來(lái)的信息 ...//渲染頁(yè)面 } }
3.SSE 使用指南請(qǐng)看Server-Sent Events 教程
SSE(Server-Sent Event,服務(wù)端推送事件)是一種允許服務(wù)端向客戶端推送新數(shù)據(jù)的HTML5技術(shù)
- 優(yōu)點(diǎn):基于HTTP而生,因此不需要太多改造就能使用,使用方便,而websocket非常復(fù)雜,必須借助成熟的庫(kù)或框架
- 缺點(diǎn):基于文本傳輸效率沒(méi)有websocket高,不是嚴(yán)格的雙向通信,客戶端向服務(wù)端發(fā)送請(qǐng)求無(wú)法復(fù)用之前的連接,需要重新發(fā)出獨(dú)立的請(qǐng)求,并且不兼容IE
source.addEventListener('open', function (event) { // ... }, false); //客戶端收到服務(wù)器發(fā)來(lái)的數(shù)據(jù),就會(huì)觸發(fā)message事件,可以在onmessage屬性的回調(diào)函數(shù)。 source.addEventListener('message', function (event) { var data = event.data; // handle message }, false); //如果發(fā)生通信錯(cuò)誤(比如連接中斷),就會(huì)觸發(fā)error事件,可以在onerror屬性定義回調(diào)函數(shù)。 source.addEventListener('error', function (event) { // handle error event }, false); //close方法用于關(guān)閉 SSE 連接。 source.close();
我們也可以自定義事件,Server-Sent Events 教程里都有明確的使用方法
4.Websocket
Websocket是一個(gè)全新的、獨(dú)立的協(xié)議,基于TCP協(xié)議,與http協(xié)議兼容、卻不會(huì)融入http協(xié)議,僅僅作為html5的一部分,其作用就是在服務(wù)器和客戶端之間建立實(shí)時(shí)的雙向通信。
- 優(yōu)點(diǎn):真正意義上的實(shí)時(shí)雙向通信,性能好,低延遲
- 缺點(diǎn):獨(dú)立與http的協(xié)議,因此需要額外的項(xiàng)目改造,使用復(fù)雜度高,必須引入成熟的庫(kù),無(wú)法兼容低版本瀏覽器
- 實(shí)現(xiàn)方式:
瀏覽器為 HTTP 通信提供了 XMLHttpRequest 對(duì)象,同樣的,也為 WebSocket 通信提供了一個(gè)通信操作接口:WebSocket。
var ws = new WebSocket("wss://echo.websocket.org"); // 當(dāng)連接建立成功,觸發(fā) open 事件 ws.onopen = function(evt) { console.log("建立連接成功 ..."); // 連接建立成功以后,就可以使用這個(gè)連接對(duì)象通信了 // send 方法發(fā)送數(shù)據(jù) ws.send("Hello WebSockets!"); }; // 當(dāng)接收到對(duì)方發(fā)送的消息的時(shí)候,觸發(fā) message 事件 // 我們可以通過(guò)回調(diào)函數(shù)的 evt.data 獲取對(duì)方發(fā)送的數(shù)據(jù)內(nèi)容 ws.onmessage = function(evt) { console.log("接收到消息: " + evt.data); // 當(dāng)不需要通信的時(shí)候,可以手動(dòng)的關(guān)閉連接 // ws.close(); }; // 當(dāng)連接斷開的時(shí)候觸發(fā) close 事件 ws.onclose = function(evt) { console.log("連接已關(guān)閉."); }
5.Web Worker
Web Worker 的作用,就是為 JavaScript 創(chuàng)造多線程環(huán)境,允許主線程創(chuàng)建 Worker 線程,將一些任務(wù)分配給后者運(yùn)行
- 優(yōu)點(diǎn):實(shí)現(xiàn)多線程環(huán)境,擺脫了js的單線程
- 缺點(diǎn):無(wú)法訪問(wèn)DOM節(jié)點(diǎn);無(wú)法訪問(wèn)全局變量或是全局函數(shù);無(wú)法調(diào)用alert()或者confirm之類的函數(shù);無(wú)法訪問(wèn)window、document之類的瀏覽器全局變量;
注意:Web Worker中的Javascript依然可以使用setTimeout(),setInterval()之類的函數(shù),也可以使用XMLHttpRequest對(duì)象來(lái)做Ajax通信 - 實(shí)例:大數(shù)據(jù)的處理;高頻的用戶交互:
- 實(shí)現(xiàn)方式:
Web workers可分為兩種類型:專用線程、共享線程。
專用線程隨當(dāng)前頁(yè)面的關(guān)閉而結(jié)束;這意味著專用線程只能被創(chuàng)建它的頁(yè)面訪問(wèn)。
與之相對(duì)應(yīng)的共享線程可以被多個(gè)頁(yè)面訪問(wèn)。
5.1、專用線程
使用 onmessage() , postmessage()通信
/** 主線程 **/ //注冊(cè)專用線程 let worker = new Worker ('worker.js') worker.onmessage = (e) => { console.log(e.data) // I post a message to main thread } worker.postMessage('main thread got a message') /** 子線程 worker.js **/ onmessage = (e) => { console.log(e.data) // main thread got a message } postMessage('I post a message to main thread') // 在主線程中終止 worker.terminate() // 在子線程中終止自身 self.close()
5.2、共享線程
SharedWorker需要用到port屬性,接收需要先connect
//注冊(cè)共享線程 let worker = new SharedWorker("sharedworker.js"); /** 主線程 **/ worker.port.onmessage = function(e){} worker.port.postMessage('data'); /** 子線程 **/ addEventListener('connect', function(event){ var port = event.ports[0] //接收 port.onmessage = function(event){ console.log(event.data); }; //發(fā)送 port.postMessage("data"); port.start(); }); // 在主線程中終止 worker.terminate() // 在子線程中終止自身 self.close()
兩種方式的錯(cuò)誤監(jiān)聽(tīng)同SSE一樣
worker.addEventListener("error", function(evt){ alert("Line #" + evt.lineno + " - " + evt.message + " in " + evt.filename); }, false); worker.postMessage(10000); });
6.Service workers
Service workers 本質(zhì)上充當(dāng)Web應(yīng)用程序與瀏覽器之間的代理服務(wù)器,也可以在網(wǎng)絡(luò)可用時(shí)作為瀏覽器和網(wǎng)絡(luò)間的代理,創(chuàng)建有效的離線體驗(yàn)。 它是 Web Worker 的一個(gè)類型
- 優(yōu)點(diǎn):可以秒開或者離線訪問(wèn)
- 缺點(diǎn):IE11 、Opera Mini 、IOS不支持
- 應(yīng)用:推送通知 —?允許用戶選擇從網(wǎng)絡(luò)應(yīng)用程序及時(shí)更新。
- 實(shí)現(xiàn)方式:
// serviceWorker.js import { register } from 'register-service-worker' if (process.env.NODE_ENV === 'production') { register('service-worker.js', { ready () { console.log( 'App is being served from cache by a service worker.' ) }, registered () { console.log('Service worker has been registered.') }, cached () { console.log('Content has been cached for offline use.') }, updatefound () { console.log('New content is downloading.') }, updated () { console.log('New content is available; please refresh.') window.location.reload(true) // 這里需要刷新頁(yè)面 }, offline () { console.log('No internet connection found. App is running in offline mode.') }, error (error) { console.error('Error during service worker registration:', error) } }) }
在 plugins 加入
plugins: [ new SWPrecacheWebpackPlugin({ cacheId: 'my-project-name', filename: 'service-worker.js', staticFileGlobs: ['dist/**/*.{js,html,css}'], minify: true, stripPrefix: 'dist/' }), new WebpackPwaManifest({ name: 'My Progressive Web App', short_name: 'MyPWA', description: 'My awesome Progressive Web App!', background_color: '#ffffff', crossorigin: 'use-credentials', //can be null, use-credentials or anonymous icons: [ { src: path.resolve('src/assets/icon.png'), sizes: [96, 128, 192, 256, 384, 512] // multiple sizes }, { src: path.resolve('src/assets/large-icon.png'), size: '1024x1024' // you can also use the specifications pattern } ] }), // ... ]
這個(gè)時(shí)候打包出來(lái)的代碼根目錄里面多了個(gè) service-worker.js ,html文件里面 pwa 相關(guān)元素也加上了。
在入口 main.js 引入該文件:
import './serviceWorker'
7、Flash Socket
在頁(yè)面中內(nèi)嵌入一個(gè)使用了Socket類的 Flash 程序JavaScript通過(guò)調(diào)用此Flash程序提供的Socket接口與服務(wù)器端的Socket接口進(jìn)行通信,JavaScript在收到服務(wù)器端傳送的信息后控制頁(yè)面的顯示。 一般用在網(wǎng)絡(luò)游戲中,web端基本不適用,加上早在 2017 年 7 月,F(xiàn)lash 的娘家 Adobe 已宣布在 2020年 底終止對(duì) Flash 的支持。各個(gè)瀏覽器也在2020年底左右終止對(duì) Flash 的支持
- 優(yōu)點(diǎn):實(shí)現(xiàn)真正的即時(shí)通信,而不是偽即時(shí)。
- 缺點(diǎn):客戶端必須安裝Flash插件;非HTTP協(xié)議,無(wú)法自動(dòng)穿越防火墻。
- 實(shí)例:網(wǎng)絡(luò)互動(dòng)游戲。
- 實(shí)現(xiàn)方式:因?yàn)槎家呀?jīng)拋棄了,加上我并非游戲類前端,我就沒(méi)了解Flash實(shí)現(xiàn)方式,有興趣的小伙伴可以自行去研究一下
8、總結(jié)
- 我在實(shí)際項(xiàng)目中,只使用過(guò)短輪詢和長(zhǎng)輪詢,其他的實(shí)時(shí)通訊方法并沒(méi)有真正使用過(guò)(業(yè)務(wù)場(chǎng)景并沒(méi)有其他需求)而且后端也給不了太多支持來(lái)實(shí)現(xiàn)是否可行。
- 長(zhǎng)輪詢與服務(wù)器的通信會(huì)比短輪詢更實(shí)時(shí),短輪詢是在采用定時(shí)器,定時(shí)器就有時(shí)間差,比如我們定時(shí)5秒鐘??赡芤幻腌妰?nèi)我們就實(shí)現(xiàn)了數(shù)據(jù)通信,那么會(huì)有4秒的等待時(shí)間。而長(zhǎng)輪詢就可以這個(gè)顧慮。
- 是否可以使用回調(diào)遞歸實(shí)現(xiàn)實(shí)時(shí)通信,可以,他類比短輪詢,但是回調(diào)遞歸并發(fā)量太大了,很容易造成服務(wù)器死機(jī),并且消耗寬帶影響到前端性能,所以我們正常不會(huì)使用回調(diào)遞歸實(shí)現(xiàn),而且回調(diào)遞歸也不叫作短輪詢。
- 為了方便以后使用,并單純的學(xué)習(xí)。
- 此次總結(jié)是看了N篇文章的結(jié)合,有不足之處,敬請(qǐng)指出。
更多關(guān)于前端實(shí)時(shí)通信方式及其優(yōu)缺點(diǎn)和實(shí)現(xiàn)方式請(qǐng)查看下面的相關(guān)鏈接
相關(guān)文章
[推薦]Win2003 服務(wù)器的詳細(xì)架設(shè)
[推薦]Win2003 服務(wù)器的詳細(xì)架設(shè)...2007-05-05Linux Apache Web 服務(wù)器(續(xù)一)
四、配置Apache基礎(chǔ)篇,讓W(xué)WW服務(wù)器跑起來(lái) Apache服務(wù)器軟件的配置文件主要有:“access.conf”:用于設(shè)置系統(tǒng)中的存取方式和環(huán)境;“httpd.conf”:用于設(shè)置服務(wù)器啟動(dòng)的基本環(huán)境;“srm.conf”:主要用于做文件資源上的設(shè)定;“mime.type”:記錄Apache服務(wù)器所能識(shí)別的MIME格式。2008-03-03什么是IIS應(yīng)用程序池以及應(yīng)用程序池詳解
什么是IIS應(yīng)用程序池以及應(yīng)用程序池詳解...2007-02-02IDC服務(wù)器托管之技術(shù)名詞解釋什么是服務(wù)器
本文介紹了什么是服務(wù)器以及IDC服務(wù)器托管之技術(shù)名詞,其中技術(shù)名詞包括服務(wù)器、U的概念CPU(CentralProcessingUnit)、硬盤、內(nèi)存、RAID、流量、帶寬等名詞的解釋2007-12-12花生殼與Windows2003 建立WEB服務(wù)器的圖文教程
花生殼與Windows2003 建立WEB服務(wù)器的圖文教程...2007-08-08三種Web開發(fā)主流技術(shù)的性價(jià)評(píng)價(jià)
三種主流技術(shù)是哪三種呢?我主要講一下ASP(ActiveX Server Page)、PHP、Java這三種技術(shù)。主要是基于我到現(xiàn)在已經(jīng)使用的以下產(chǎn)品而談:2008-03-03