最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript前端巧妙實(shí)現(xiàn)數(shù)據(jù)實(shí)時更新詳解

 更新時間:2025年03月20日 16:03:34   作者:悲傷玉米排骨湯l  
作為開發(fā)者,我們常面對復(fù)雜的開發(fā)環(huán)境,要應(yīng)對即時通訊與數(shù)據(jù)實(shí)時更新的問題,那么該如何精準(zhǔn)高效實(shí)現(xiàn)這些功能呢,下面小編就來和大家簡單講講

一、前言

如今,Web 應(yīng)用愈發(fā)復(fù)雜,用戶對實(shí)時交互體驗(yàn)的要求也越來越高,比如:社媒的即時通訊、大屏的數(shù)據(jù)更新、實(shí)時消息的提醒等,這些都表明實(shí)時交互已成高品質(zhì)應(yīng)用的必備特性。而作為開發(fā)者,我們常面對復(fù)雜的開發(fā)環(huán)境,要應(yīng)對即時通訊與數(shù)據(jù)實(shí)時更新的問題。那么,該如何精準(zhǔn)高效實(shí)現(xiàn)這些功能呢?我們將共同探討下,輪詢、Web Socket SSE(Server-Sent Events) 三種解決方案,最終根據(jù)當(dāng)下場景選出最優(yōu)方案,打造更為出色的產(chǎn)品。

二、方案一:輪詢(Polling)

1. 短輪詢

實(shí)現(xiàn)短輪詢,我們可以采用定時器的方式來實(shí)現(xiàn),讓客戶端每隔較短固定時間就向服務(wù)端發(fā)起請求,無論服務(wù)器有無新消息,都會正常給予回應(yīng)。
短輪詢的優(yōu)劣勢一目了然。優(yōu)勢在于,容易理解、實(shí)現(xiàn)過程簡便,同時兼容性又很好,在幾乎所有支持 HTTP 協(xié)議的瀏覽器及服務(wù)器環(huán)境都能很好的運(yùn)行短輪詢。不過,缺點(diǎn)也非常顯而易見。當(dāng)按照很短的固定時間間隔去頻繁請求數(shù)據(jù),如果此時的數(shù)據(jù)并未更新,這些請求就成了無效請求,但是每一個無效的請求都得完成 HTTP 建立連接的一系列流程,像三次握手 、 四次揮手 ,這無疑造成了不必要的資源浪費(fèi)。同時也是由于按固定間隔請求,數(shù)據(jù)更新也可能會存在延遲的現(xiàn)象,在要求實(shí)時性的場景下就不滿足了。

2. 長輪詢

相對于短輪詢,長輪詢的實(shí)現(xiàn)過程會復(fù)雜一些。首先,同樣是由客戶端向服務(wù)端發(fā)送HTTP請求后,不過與短輪詢的差別在于,服務(wù)器接到請求后并不即刻返回響應(yīng),而是選擇將該請求暫時掛起,靜靜等待數(shù)據(jù)更新,或是直至達(dá)到特定的超時時間(這個超時時間通常比短輪詢間隔長)。在等待期間,如果有數(shù)據(jù)更新了,就會立即將新數(shù)據(jù)返回給客戶端,若一直未等到數(shù)據(jù)更新,直到達(dá)到超時時間,服務(wù)器才返回一個空響應(yīng)或者告知客戶端無新數(shù)據(jù)。客戶端收到響應(yīng)后,無論是否有新數(shù)據(jù),都會立即再次發(fā)起新的長輪詢請求,如此循環(huán)往復(fù)。

這種長輪詢方式相較短輪詢存在一定優(yōu)勢,首先減少了無效請求的次數(shù),因?yàn)橹挥性跀?shù)據(jù)更新的時候,服務(wù)器才會響應(yīng),實(shí)時性得到了增強(qiáng),也同時在一定程度上節(jié)省了網(wǎng)絡(luò)資源。長輪詢雖然減少了無效請求,但是長時間掛起的請求仍會占用服務(wù)器的內(nèi)存、線程等關(guān)鍵資源。若同時存在大量長輪詢請求,且長時間處于等待數(shù)據(jù)更新狀態(tài),服務(wù)器資源可能會被大量消耗,同樣可能引發(fā)性能問題。

由此可見, 無論是運(yùn)用長輪詢還是短輪詢策略,在對實(shí)時性有著嚴(yán)格要求的場景之下這都不是一個非常好的方案。一方面,頻繁的無效請求以及長時間掛起的連接,極易造成服務(wù)器資源的浪費(fèi)。另一方面,由于輪詢時間間隔的固定性,一旦設(shè)置的不合理,就可能錯失數(shù)據(jù)更新的最佳時機(jī),無法及時將關(guān)鍵信息推送給客戶端,導(dǎo)致實(shí)時交互出現(xiàn)延遲。

三、方案二:Web Socket

Web Socket 是一種基于單個 TCP 連接的協(xié)議,擁有實(shí)現(xiàn) 全雙工 通信的能力。它讓客戶端和服務(wù)端可以雙向、實(shí)時傳輸數(shù)據(jù),擺脫了傳統(tǒng) HTTP 請求那種請求 - 響應(yīng)模式的限制。有了 Web Socket,服務(wù)器能隨時主動給客戶端推送消息,客戶端也能馬上向服務(wù)器發(fā)數(shù)據(jù),就如同構(gòu)建起了一條實(shí)時雙向通道。

1.Web Socket通信原理

握手階段

初始請求階段

  • 首先,我們可以從下圖實(shí)現(xiàn)效果中看出來,起始于客戶端向服務(wù)端發(fā)送了一個HTTP請求,但這個請求和常規(guī)的HTTP請求又不太一致,他包含了兩個特殊的請求頭, Upgrade: websocket  和  Connection: Upgrade。
  • Upgrade: websocket 像是一個信號,它的作用就是用來告知服務(wù)器,客戶端希望將當(dāng)前的通信協(xié)議從 HTTP升級為Web Socket協(xié)議。
  • Connection: Upgrade 是與Upgrade: websocket 進(jìn)行配合使用的,它的作用是告訴服務(wù)器,不要把這個請求當(dāng)作普通的 HTTP 請求來處理,而是要關(guān)注 “Upgrade” 請求頭中的內(nèi)容,按照要求進(jìn)行協(xié)議的升級。

服務(wù)器響應(yīng)階段

服務(wù)器收到客戶端的升級請求后,如果支持 Web Socket 協(xié)議,就會返回一個響應(yīng)來完成握手過程。響應(yīng)狀態(tài)碼通常是 101,表示 協(xié)議切換。響應(yīng)頭也會包含和客戶端請求對應(yīng)的 UpgradeConnection 字段,確認(rèn)連接升級。Sec - WebSocket - Accept ,它是根據(jù)客戶端請求中的 Sec - WebSocket - Key 生成的,用于安全驗(yàn)證。通過這個握手過程,雙方就建立了一個穩(wěn)定的 Web Socket 連接這樣,這個連接是基于 TCP的,為后續(xù)的雙向通信做好了準(zhǔn)備。

數(shù)據(jù)傳輸階段

我們從下圖中可以看出,Web socket全雙工通道的特點(diǎn),客戶端可以向服務(wù)端主動發(fā)送消息,服務(wù)端也可以推送數(shù)據(jù)到服務(wù)端。具體的數(shù)據(jù)格式,我們可以通過抓包軟件來進(jìn)行抓包看下。

連接維護(hù)和關(guān)閉階段

在整個通信過程中,Web Socket 協(xié)議要求客戶端和服務(wù)器都要維護(hù)連接的狀態(tài)。連接狀態(tài)包括連接是否打開、正在關(guān)閉或者已經(jīng)關(guān)閉等??蛻舳撕头?wù)器通過心跳機(jī)制(發(fā)送周期性的小數(shù)據(jù)包來檢測對方是否還在線)或者其他自定義的連接檢測方法來確保連接的穩(wěn)定性。

當(dāng)需要關(guān)閉 WebSocket 連接時,無論是客戶端還是服務(wù)器都可以發(fā)起關(guān)閉請求。關(guān)閉請求也是通過發(fā)送一個特定的幀(關(guān)閉幀)來實(shí)現(xiàn)的。對方在收到關(guān)閉幀后,會進(jìn)行一些必要的清理工作,如釋放資源等,然后關(guān)閉連接。

2.示例

模擬客戶端代碼

<div id="app">
  <input v-model="message" placeholder="輸入要發(fā)送的消息" />
  <button @click="sendMessage">發(fā)送消息</button>
  <div>
    <h3>收到的回復(fù)記錄:</h3>
    <ul>
      <li v-for="(msg, index) in receivedMessages" :key="msg">{{ msg }}</li>
    </ul>
  </div>
</div>
 
<script>
  const app = new Vue({
    el: "#app",
    data() {
      return {
        message: "",
        receivedMessages: [], // 新增數(shù)組用于存儲所有收到的消息
        socket: null,
      };
    },
    mounted() {
      // 創(chuàng)建WebSocket連接,這里的地址要和后端服務(wù)器監(jiān)聽的地址對應(yīng),這里假設(shè)后端在本地3000端口
      this.socket = new WebSocket("ws://localhost:3000");
      // 連接成功時觸發(fā)的事件
      this.socket.addEventListener("open", () => {
        console.log("已連接到WebSocket服務(wù)器");
      });
      // 接收服務(wù)器發(fā)送消息的事件
      this.socket.addEventListener("message", (event) => {
        const receivedMsg = event.data;
        this.receivedMessages.push(receivedMsg); // 將收到的消息添加到數(shù)組中
      });
      // 連接關(guān)閉時觸發(fā)的事件
      this.socket.addEventListener("close", () => {
        console.log("與WebSocket服務(wù)器的連接已關(guān)閉");
      });
    },
    methods: {
      sendMessage() {
        if (this.socket.readyState === WebSocket.OPEN) {
          this.socket.send(this.message);
          this.message = "";
        } else {
          console.log("WebSocket連接未就緒,無法發(fā)送消息");
        }
      },
    },
  });
</script>

模擬服務(wù)端發(fā)送請求

注意:下方代碼中,定時器僅用來模擬,在實(shí)際業(yè)務(wù)中應(yīng)該替換為業(yè)務(wù)代碼

const WebSocket = require('ws');
 
// 創(chuàng)建WebSocket服務(wù)器實(shí)例,監(jiān)聽在3000端口,你可以根據(jù)需求修改端口號
const wss = new WebSocket.Server({ port: 3000 });
 
// 用于存儲已連接的客戶端WebSocket實(shí)例,方便后續(xù)向所有客戶端發(fā)送消息等操作
const clients = [];
 
// 當(dāng)有客戶端連接時觸發(fā)的事件
wss.on('connection', (ws) => {
  console.log('客戶端已連接');
  clients.push(ws);
 
  // 接收客戶端發(fā)送的消息
  ws.on('message', (message) => {
    console.log(`收到客戶端消息: ${message}`);
    // 這里簡單地將收到的消息加上一個后綴后再發(fā)回客戶端
    const responseMessage = `你發(fā)送的消息是:${message}`;
    ws.send(responseMessage);
  });
 
  // 當(dāng)客戶端關(guān)閉連接時觸發(fā)的事件
  ws.on('close', () => {
    console.log('客戶端已斷開連接');
    const index = clients.indexOf(ws);
    if (index > -1) {
      clients.splice(index, 1);
    }
  });
});
 
// 【注意: 模擬一個定時任務(wù),每隔1秒向所有已連接的客戶端發(fā)送一條消息,你可以編寫自己的業(yè)務(wù)代碼】
setInterval(() => {
  const messageToSend = '這是服務(wù)端主動發(fā)送的消息,當(dāng)前時間:' + new Date().toLocaleString();
  clients.forEach((client) => {
    if (client.readyState === WebSocket.OPEN) {
      client.send(messageToSend);
    }
  });
}, 1000);
 
console.log('WebSocket服務(wù)器已啟動,正在監(jiān)聽3000端口...');

實(shí)現(xiàn)效果

3.特點(diǎn)

相較于傳統(tǒng)的 HTTP 請求,Web Socket 在實(shí)時性方面展現(xiàn)出了卓越優(yōu)勢,它打破了以往被動等待響應(yīng)的模式,服務(wù)器得以實(shí)時且主動地將數(shù)據(jù)推送至客戶端。在面對高實(shí)時性的場景下,大大的提升了用戶體驗(yàn)。并且只需建立一次 TCP 連接,后續(xù)數(shù)據(jù)傳輸高效便捷,既減少了網(wǎng)絡(luò)帶寬的無謂占用,又減輕了服務(wù)器頻繁處理連接請求的負(fù)擔(dān)。然而,當(dāng)應(yīng)用場景出現(xiàn)變化,假設(shè)客戶端僅僅是獲取服務(wù)端推送的消息,自身并無向服務(wù)端發(fā)送信息的需求,此時,我們可以考慮下 SSE(Server-Sent Events)這個方案。

四、方案三:SSE

SSE(Server-Sent Events) 同樣具備了服務(wù)端主動向客戶端推送數(shù)據(jù)的能力,而無需客戶端不斷地發(fā)起請求。與Web Socket不同的是,SSE 是基于 HTTP 協(xié)議的,使用的是單向通信, 而Web Socket是基于TCP協(xié)議的,使用的話雙向通信。

1.SSE通信原理

客戶端發(fā)起請求

客戶端需要發(fā)送一個特定的請求告知服務(wù)器準(zhǔn)備接收事件。在傳統(tǒng)的 HTTP 請求 - 響應(yīng)模式中,一次請求完成后連接通常會關(guān)閉,但 SSE 通過在服務(wù)器端和客戶端設(shè)置特定的頭部信息,讓連接持續(xù)開啟。例如:設(shè)置了Content - Type頭部為text/event - stream,并設(shè)置Cache - Controlno - cache以及Connection為keep - alive,這樣告知客戶端,這是一個 SSE 連接,數(shù)據(jù)會持續(xù)推送,并且不需要緩存數(shù)據(jù)??蛻舳酥恍柘蚍?wù)器發(fā)送一個普通的 HTTP 請求,指向服務(wù)器端提供 SSE 服務(wù)的特定端點(diǎn)就行,例如/events,就可以順利開啟SSE連接。

服務(wù)器響應(yīng)請求

服務(wù)器收到客戶端請求后,會維持一個長連接,并且定期向客戶端發(fā)送事件數(shù)據(jù)。每個事件都是通過特定的格式(例如 data:\n\n)發(fā)送給客戶端的。

客戶端接收數(shù)據(jù)

客戶端通過 JavaScript 的 EventSource 對象接收從服務(wù)器推送過來的數(shù)據(jù)。這些數(shù)據(jù)可以是普通文本,也可以是 JSON 格式的對象,取決于服務(wù)器如何發(fā)送。

事件流的關(guān)閉

一旦不再需要推送數(shù)據(jù),比如客戶端主動關(guān)閉連接,又或是中途出現(xiàn)錯誤,導(dǎo)致無法繼續(xù)推送時,服務(wù)器便會果斷關(guān)閉連接。

2.示例

服務(wù)端,使用express框架為例

注意:下方代碼中,定時器僅用來模擬,在實(shí)際業(yè)務(wù)中應(yīng)該替換為業(yè)務(wù)代碼

const express = require('express');
const app = express();
const port = 3000;
 
// 設(shè)置響應(yīng)頭,表明這是一個SSE流
app.get('/events', (req, res) => {
    res.setHeader('Content-Type','text/event-stream');
    res.setHeader('Cache-Control', 'no-cache');
    res.setHeader('Connection', 'keep-alive');
 
    // 【注意:模擬定時發(fā)送數(shù)據(jù)(實(shí)際應(yīng)用中需要根據(jù)真實(shí)業(yè)務(wù)邏輯觸發(fā)發(fā)送)?。?!】
    const interval = setInterval(() => {
        const data = `data: { "time": "${new Date().toLocaleString()}"}\n\n`;
        res.write(data);
    }, 3000);
 
    // 當(dāng)客戶端關(guān)閉連接時,清除定時器
    req.on('close', () => {
        clearInterval(interval);
    });
});
 
app.listen(port, () => {
    console.log(`服務(wù)器運(yùn)行在 http://localhost:${port}`);
});

模擬客戶端代碼

mounted() {
  const source = new EventSource('http://localhost:3000/events');
  source.onmessage = (event) => {
      const data = JSON.parse(event.data); // data 就是發(fā)送的消息
      this.message = data.message;
  };
  source.onerror = (error) => {
      console.log('SSE連接出錯:', error);
  };
}

實(shí)現(xiàn)效果

3.特點(diǎn)

對于SSE來說,優(yōu)勢上在于簡單易用,客戶端用 EventSource可以接收,服務(wù)器端定期發(fā)數(shù)據(jù)即可推送。且單向通信、基于長連接,服務(wù)器資源消耗低。不過,SSE 是有局限的。只能夠進(jìn)行單向通信,現(xiàn)代瀏覽器大多支持,但是IE或者舊版本瀏覽器不支持。SSE 只支持文本格式的數(shù)據(jù)流,不支持二進(jìn)制數(shù)據(jù)傳輸。總之,SSE 在合適場景能發(fā)揮優(yōu)勢,支撐實(shí)時數(shù)據(jù)推送需求。

五、總結(jié)

上述文章中,介紹了輪詢、Web Socket、SSE 三種方案。適合的場景也有一些差別,例如:輪詢的方式可以在更新頻率不高的場景下使用、Web Socket可以在需要雙向交互的場景下使用、SSE適用于服務(wù)器到客戶端的單向數(shù)據(jù)流的場景下使用。開發(fā)者可以根據(jù)場景選擇最優(yōu)方案,提升產(chǎn)品實(shí)時交互體驗(yàn)。

以上就是JavaScript前端巧妙實(shí)現(xiàn)數(shù)據(jù)實(shí)時更新詳解的詳細(xì)內(nèi)容,更多關(guān)于JavaScript數(shù)據(jù)實(shí)時更新的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • js控制一個按鈕是否可點(diǎn)擊(可使用)disabled的實(shí)例

    js控制一個按鈕是否可點(diǎn)擊(可使用)disabled的實(shí)例

    下面小編就為大家?guī)硪黄猨s控制一個按鈕是否可點(diǎn)擊(可使用)disabled的實(shí)例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-02-02
  • 獲取layer.open彈出層的返回值方法

    獲取layer.open彈出層的返回值方法

    今天小編就為大家分享一篇獲取layer.open彈出層的返回值方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-08-08
  • 小程序如何實(shí)現(xiàn)中間帶加號的tabbar

    小程序如何實(shí)現(xiàn)中間帶加號的tabbar

    自定義tabBar可以讓開發(fā)者更加靈活地設(shè)置tabBar樣式,以滿足更多個性化的場景,下面這篇文章主要給大家介紹了關(guān)于小程序如何實(shí)現(xiàn)中間帶加號tabbar的相關(guān)資料,需要的朋友可以參考下
    2022-04-04
  • JavaScript模擬文件拖選框樣式v1.0的實(shí)例

    JavaScript模擬文件拖選框樣式v1.0的實(shí)例

    下面小編就為大家?guī)硪黄狫avaScript模擬文件拖選框樣式v1.0的實(shí)例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-08-08
  • 小程序登錄/注冊頁面設(shè)計的實(shí)現(xiàn)代碼

    小程序登錄/注冊頁面設(shè)計的實(shí)現(xiàn)代碼

    這篇文章主要介紹了小程序登錄/注冊頁面設(shè)計的實(shí)現(xiàn)代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • 小程序中實(shí)現(xiàn)自定義頭部導(dǎo)航組件的詳細(xì)過程

    小程序中實(shí)現(xiàn)自定義頭部導(dǎo)航組件的詳細(xì)過程

    這篇文章主要介紹了小程序中實(shí)現(xiàn)自定義頭部導(dǎo)航組件的詳細(xì)過程,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2024-06-06
  • javascript單例模式的簡單實(shí)現(xiàn)方法

    javascript單例模式的簡單實(shí)現(xiàn)方法

    這篇文章主要介紹了javascript單例模式的簡單實(shí)現(xiàn)方法,以javascript創(chuàng)建唯一實(shí)例的形式分析了javascript單例模式的簡單實(shí)現(xiàn)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-07-07
  • JS封裝的三級聯(lián)動菜單(使用時只需要一行js代碼)

    JS封裝的三級聯(lián)動菜單(使用時只需要一行js代碼)

    在實(shí)際的項(xiàng)目開發(fā)中,我們經(jīng)常需要三級聯(lián)動,比如省市區(qū)的選擇,商品的三級分類的選擇等等。這篇文章主要介紹了JS封裝的三級聯(lián)動菜單(使用時只需要一行js代碼)的相關(guān)資料,需要的朋友可以參考下
    2016-10-10
  • js實(shí)現(xiàn)網(wǎng)站首頁圖片滾動顯示

    js實(shí)現(xiàn)網(wǎng)站首頁圖片滾動顯示

    網(wǎng)站首頁圖片滾動顯示對于很多朋友都有很大的吸引,因?yàn)樗梢詭硪庀氩坏揭曈X沖擊效果,接下來本文也實(shí)現(xiàn)一下,感興趣的朋友可以參考下,或許對你學(xué)習(xí)js知識有所幫助
    2013-02-02
  • 下拉框select的綁定示例

    下拉框select的綁定示例

    根據(jù)文本綁定text、根據(jù)值綁定value,下面有個不錯的示例,大家可以看看
    2014-09-09

最新評論

廊坊市| 新余市| 乌恰县| 崇信县| 宜州市| 万年县| 东光县| 蒙山县| 嘉峪关市| 长白| 偃师市| 灵丘县| 蛟河市| 新乡市| 长兴县| 西乡县| 石家庄市| 桦南县| 儋州市| 崇左市| 宝鸡市| 若羌县| 新津县| 宝丰县| 天等县| 且末县| 柳州市| 武川县| 日照市| 永泰县| 山阳县| 辉县市| 萝北县| 聂拉木县| 广南县| 乐安县| 忻城县| 视频| 吴旗县| 微博| 遵义市|