隨手扎
你可能不知道的即時更新方案:Polling
靜態網頁 & 動態網頁
全球資訊網路(World Wide Web, WWW)最早用於學術研究機構,用於分享研究報告成果。起初常見型態為:資訊分享者自行建立Web伺服器,提供HTML靜態頁面,讓資訊受者透過瀏覽器取得資訊。
英國科學家提姆·柏內茲-李於1989年發明了全球資訊網。1990年他在瑞士CERN的工作期間編寫了第一個網頁瀏覽器。網頁瀏覽器於1991年1月向其他研究機構發行,並於同年8月向公眾開放。1
「資訊分享者自行建立Web伺服器,提供HTML靜態頁面,讓資訊受者透過瀏覽器取得資訊」這從現在來看,可能分成兩個不同維度的類型:
- Web 1.0: 資訊分享者自行建立Web伺服器。用戶只能單向被動的接受由權威內容服務提供商提供的內容,用戶大部分為內容消費者,而網站則由內容驅動2
- 靜態內容網頁。網頁內容並不會因為內容接收者的不同、時間地區的不同而有所不同。
隨後出現部落格平台、線上論壇,出現可以提供資訊內容的網站使用者。在此,網站內容不再簡單以HTMl方式儲存,更多的內容儲存於資料庫,由使用者提供,動態的提供給瀏覽器。這是 動態網頁 和 Web 2.0 。
此外伴隨者瀏覽器腳本語言與API的逐漸統一,確立了 ECMAScript / JavaScript 在瀏覽器的地位,結束了過往百家爭鳴的情況(不過現在還有一些原生支援特殊腳本語言的瀏覽器存在,但JavaScript已成主流)。 似動非動,吸引人眼球由JS、CSS建立動畫效果的網頁內容開始玲瑯滿目地出現。
1996年11月,網景正式向ECMA(歐洲電腦製造商協會)提交語言標準。1997年6月,ECMA以JavaScript語言為基礎制定了ECMAScript標準規範ECMA-262。JavaScript成為了ECMAScript最著名的實現之一。除此之外,ActionScript和JScript也都是ECMAScript規範的實作語言。3
其中也還有另一個令人興奮、今天廣泛使用的技術出現: Ajax(Asynchronous JavaScript and XML)。
在現今,Ajax技術主要以XMLHttpRequest
和fetch
兩個API呈現。也可能隱藏在jQuery4、Axios等比較高層次的套件函式庫之下。
這也使得由瀏覽器處理、在前端渲染生成不同內容的畫面成為可能。儘管這不是當前唯一的技術方式,但有許多別具特色的功能、前後分離的網站都依賴者這項能力。
接著就讓我們來探索幾個取得更新資訊的模式吧!
前端頁面內容即時更新方案
並非由後端伺服器選染產生HTML畫面的做法5,主要分有Polling、Long Polling、Websocket還有WebRTC。此外還有比要少見的Server Send Event和multipart/x-mixed-replace
這兩種處理方式。
本小節除了WebRTC,會探索一下其他的做法。
Polling
Polling輪詢。是一種透過Ajax技術不斷去取得新內容的方式。透過Ajax發出的Request和得到的Response遵循著通常的狀態,正常內容會在一定時間內返回,否則視為超時(timeout)。
返回內容依據需求實現。若資源沒有更新,回傳空內容或是舊內容;否則回傳新內容。
實際上超時對於應用整體而言也沒什麼影響,因爲會在下一次取得新的內容。通常而言,在取得內容後也不會立刻再詢問一次新內容。視需要即時更新的情況與內容通常更新的情況,會設置一段間格時間。
由於實現簡單,目前還有不少設計可以見得其身影。
優點
對於一般的Web架構來說,後端架構幾乎無需調整。前端視需要即時更新的情況與內容通常更新的情況,決定何時需要取得新的內容資訊。是由前端,需要呈現資料的一方主動拉取。
缺點
內容並非即時。由於是由前端主動詢問拉取的,而且通常而言每次詢問間會有一段間格時間。這段間格時間並不保持雙方連線。因此可能存在資料內容不即時的問題。
此外,由於每次Request可能都是獨立的TCP連線,因此都需要經過TCP的三段式交握連線。這段於網絡消耗而言是而外的看不見的負擔。
這是發生在TCP協議上。HTTP/0.9、HTTP/1.0、HTTP/2.0 都是基於 TCP ,可能發生這個情況。但是 HTTP/3 是基於QUIC,而該是基於UDP下的,可能就沒有影響。
Lab
由於Polling非常簡單,因此實驗環境需求也非常簡單。
這裡將透過docker建立一個Nginx服務器。
如果你安裝了Python,也可以透過python -m http.server
執行Python自帶的簡易伺服器。
收先先建立www-data
的資料夾。然後透過docker啓動Nginx:
docker run --name nginx --rm -p 8080:80 -v "${PWD}/www-data":/usr/share/nginx/html nginx
在www-data
資料夾下建立一份content.txt
,並寫入Hello World
的內容。
若資源沒有更新,回傳空內容或是舊內容
對於沒有更新的資源內容,將會回傳就有的內容。因此前端顯式時只需要每次都取代原本顯式內書仍即可。
然後同樣在www-data
資料夾建立index.html
:
<!-- www-data/index.html -->
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>即時更新內容 - Polling</title>
</head>
<body>
<h1 id="content"></h1>
</body>
<script defer type="module">
const delay = 5000/*ms*/;
const contentEl = document.querySelector('#content');
let timer = null;
async function updateContent(){
let response = await fetch('/content.txt')
contentEl.innerText = await response.text();
timer = setTimeout( updateContent , delay);
}
updateContent();
</script>
</html>
現在,我們可以透過 http://localhost:8080 去瀏覽這個頁面。
這個頁面會每隔5秒去取得一次content.txt
的內容,並顯示在畫面上。所以你可以將content.txt
改成:
Hello Bob!
在5秒內,畫面應該就會更新成新的content.txt
的內容。
參考資料
本系列文參加 iT邦幫忙 的 2022鐵人賽
參賽主題: 這些那些你可能不知道我不知道的Web技術細節
維基百科-全球資訊網。取用時間:2022.08.30。 ↩︎
維基百科-Web1.0。取用時間:2022.08.30。 ↩︎
維基百科-JavaScript。取用時間:2022.08.30。 ↩︎
什麼是jQuery?前端框架盛行還需要JavaScript函式庫嗎?。取用時間:2022.09.01。 ↩︎
在此,將選染畫面分成兩個部分。一個部分是瀏覽器根據HTML、CSS生成實際顯示的畫面;另一個是生成HTML、CSS的原始資料內容。此處主要指後者。 ↩︎