改善網路視訊直播系統的效能和程式碼質量,應該怎麼做?

雲豹科技程式設計師發表於2021-09-29


在網路視訊直播系統中,我們的網頁通常需要向伺服器傳送多個 HTTP 請求。
假設我們的網路視訊直播系統具有一項功能,即每當使用者單擊 li 標記時,客戶端都會向伺服器傳送一個 HTTP 請求。
這是一個簡單的 Demo:

<html>
  <body>
    <ul>
      <li>1</li>
      <li>2</li>
      <li>3</li>
      <li>4</li>
      <li>5</li>
      <li>6</li>
      <li>7</li>
      <li>8</li>
      <li>9</li>
    </ul>
    <script>
      // Suppose this function is used to make HTTP requests to the server
      var sendHTTPRequest = function(message) {
        console.log(
          "Start sending HTTP message to the server: ",
          message        );
        console.log("1000ms passed");
        console.log("HTTP Request is completed");
      };
      var ul = document.getElementsByTagName("ul")[0];
      ul.onclick = function(event) {
        if (event.target.nodeName === "LI") {
          // Executes this function every time the <li> tag is clicked.
          sendHTTPRequest(event.target.innerText);
        }
      };
    </script>
  </body></html>

在上面的程式碼中,我們直接使用簡單的 sendHTTPRequest 函式來模擬傳送 HTTP 請求。這樣做是為了更好地專注於核心目標,因此我簡化了一些程式碼。

然後,我們將 click 事件繫結到 ul 元素。每次使用者單擊諸如

  • 5
  • 之類的標記時,網路視訊直播系統客戶端將執行 sendHTTPRequest 函式以向伺服器發出 HTTP 請求。

當然,在真實的網路視訊直播系統開發中,我們可能會向伺服器傳送一個檔案,推送通知,或者傳送一些日誌。但為了演示的慣例,我們將跳過這些細節。

好了,這是一個很簡單的演示,那麼上面的程式碼有沒有什麼缺點呢?

如果您的網路視訊直播系統非常簡單,那麼編寫這樣的程式碼應該沒有問題。但是,如果您的網路視訊直播系統很複雜,並且客戶端需要頻繁向伺服器傳送 HTTP 請求,則此程式碼效率很低。

在上面的示例中,如果任何使用者反覆快速單擊 li 元素會發生什麼?這時,我們的網路視訊直播系統客戶端需要向伺服器發出頻繁的 HTTP 請求,並且每個請求都會消耗大量時間和伺服器資源。

網路視訊直播系統客戶端每次與伺服器建立新的 HTTP 連線時,都會消耗一些時間和伺服器資源。因此,在 HTTP 傳輸機制中,一次傳輸所有檔案比多次傳輸少量檔案更為有效。

例如,您可能需要傳送五個 HTTP 請求,每個 HTTP 請求的 HTTP 資料包大小為 1MB。現在,您一次傳送一個 HTTP 請求,資料包大小為 5MB。通常預期後者的效能要比前一個更好。

網頁上的大量 HTTP 請求可能會減慢網頁的載入時間,最終損害網路視訊直播系統使用者體驗。如果載入速度不夠快,這可能會導致訪問者更快地離開該頁面。

因此,在這種情況下,我們可以考慮合併 HTTP 請求。

在我們目前的網路視訊直播系統中,我的思路是這樣的:我們可以在本地設定一個快取,然後在一定範圍內收集所有需要傳送給伺服器的訊息,然後一起傳送。

你可以暫停一下,自己試著想辦法。

提示:您需要建立一個本地快取物件來收集需要傳送的訊息。然後,您需要使用定時器定時傳送收集到的訊息。

這是一個實現。

在這裡插入圖片描述

var messages = [];var timer;var sendHTTPRequest = function(message) {
  messages.push(message);
  if (timer) {
    return;
  }
  timer = setTimeout(function() {
    console.log(
      "Start sending messages: ",
      messages.join(",")
    );
    console.log("1000ms passed");
    console.log("HTTP Request is completed.");
    clearTimeout(timer);
    timer = null;
    messages = [];
  }, 2000);};

每當網路視訊直播系統客戶端需要傳送訊息,也就是觸發一個 onclick 事件的時候,sendHTTPRequest 並不會立即向伺服器傳送訊息,而是先將訊息快取在訊息中。然後,我們有一個計時器,該計時器在 2 秒鐘後執行,並且在 2 秒鐘後,該計時器會將所有先前快取的訊息傳送到伺服器。此更改達到了組合 HTTP 請求的目的。

儘管我們多次觸發點選事件,但在兩秒鐘內,我們只傳送了一個 HTTP 請求。

當然,為了方便演示,我將等待時間設定為 2 秒。如果你覺得這個等待時間太長,你可以縮短這個等待時間。

對於不需要太多實時互動的專案,2 秒的延遲並不是一個巨大的副作用,但它可以減輕伺服器的很多壓力。在適當的情況下,這是非常值得的。

上面的程式碼確實為網路視訊直播系統提供了一些效能改進。但是就程式碼設計而言,上面的程式碼並不好。

第一,違反了單一責任原則。sendHTTPRequest 函式不僅向伺服器傳送 HTTP 請求,而且還組合 HTTP 請求。該函式執行過多操作,使程式碼看起來非常複雜。

如果網路視訊直播系統某個功能(或物件)承擔了過多的責任,那麼當我們的需求發生變化時,該功能通常將不得不發生重大變化。這樣的設計不能有效地應對可能的更改,這是一個糟糕的設計。

我們理想的程式碼如下所示:
在這裡插入圖片描述
我們沒有對 sendHTTPRequest 進行任何更改,而是選擇為其提供代理。這個代理函式執行合併 HTTP 請求的任務,並將合併後的訊息傳遞給 sendHTTPRequest 傳送。然後我們以後就可以直接使用 proxySendHTTPRequest 方法了。

您可以暫停片刻,然後嘗試自己解決。

這是一個實現:
在這裡插入圖片描述

var proxySendHTTPRequest = (function() {
  var messages = [],
    timer;
  return function(message) {
    messages.push(message);
    if (timer) {
      return;
    }
    timer = setTimeout(function() {
      sendHTTPRequest(messages.join(","));
      clearTimeout(timer);
      timer = null;
      messages = [];
    }, 2000);
  };})();

其基本思想與前面的程式碼類似,該程式碼使用 messages 變數在一定時間內快取所有訊息,然後通過計時器統一地傳送它們。此外,這段程式碼使用了閉包技巧,將 messages 和 timer 變數放在區域性作用域中,以避免汙染全域性名稱空間。

這段程式碼與前面的程式碼最大的區別是它沒有更改 sendHTTPRequest 函式,而是將其隱藏在 proxySendHTTPRequest 後面。我們不再需要直接訪問 sendHTTPRequest,而是使用代理 proxySendHTTPRequest 來訪問它。proxySendHTTPRequest 與sendHTTPRequest 具有相同的引數列表和相同的返回值。

這樣的設計有什麼好處?

  • 傳送 HTTP 請求和合並 HTTP
    請求的任務交給了網路視訊直播系統兩個不同的函式,每個函式專注於一個職責。它遵從單一責任原則,並使程式碼更容易理解。
  • 由於兩個函式的引數是相同的,我們可以簡單地用 proxySendHTTPRequest 替換 sendHTTPRequest
    的位置,而不需要做任何重大更改。

想象一下,如果將來網路效能有所提高,或者由於某些其他原因,我們不再需要合併 HTTP 請求。在這一點上,如果我們使用以前的設計,我們將不得不再次大規模地更改程式碼。在當前的程式碼設計中,我們可以簡單地替換函式名。

事實上,這個編碼技巧通常被稱為設計模式中的代理模式。

所謂的代理模式,其實在現實生活中很好理解。

  • 比方說,你想訪問一個網站,但你不想洩露你的 IP 地址。那麼你可以使用
    VPN,先訪問你的代理伺服器,然後通過代理伺服器訪問目標網站。這樣目標網站就無法知道你的 IP 地址了。
  • 有時候,你會把你的真實伺服器隱藏在 Nginx 伺服器後面,讓 Nginx 伺服器為你的真實伺服器處理一些瑣碎的操作。

這些都是現實生活中代理模式的例子。

我們不需要為代理模式(或任何其他設計模式)的正式定義而煩惱,我們只需要知道,當網路視訊直播系統客戶端沒有直接訪問它的便利(或能力)時,我們可以提供代理功能(或物件)來控制對目標功能(或物件)的訪問即可。客戶機實際上訪問代理函式(或物件),代理函式對請求進行一些處理,然後將請求傳遞給目標。

本文轉載自網路,轉載僅為分享乾貨知識,如有侵權歡迎聯絡雲豹科技進行刪除處理
原文連結:https://blog.zhangbing.site/2021/03/12/improve-both-app-performance-and-code-quality-combining-http-requests-by-proxy-pattern/

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69996194/viewspace-2794452/,如需轉載,請註明出處,否則將追究法律責任。

相關文章