整合營銷服務(wù)商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          HTML頁面基本結(jié)構(gòu)和加載過程

          家好,我是皮皮。

          前言

          對于前端來說,HTML 都是最基礎(chǔ)的內(nèi)容。

          今天,我們來了解一下 HTML 和網(wǎng)頁有什么關(guān)系,以及與 DOM 有什么不同。通過本講內(nèi)容,你將掌握瀏覽器是怎么處理 HTML 內(nèi)容的,以及在這個過程中我們可以進(jìn)行怎樣的處理來提升網(wǎng)頁的性能,從而提升用戶的體驗。


          一、瀏覽器頁面加載過程

          不知你是否有過這樣的體驗:當(dāng)打開某個瀏覽器的時候,發(fā)現(xiàn)一直在轉(zhuǎn)圈,或者等了好長時間才打開頁面……

          此時的你,會選擇關(guān)掉頁面還是耐心等待呢?

          這一現(xiàn)象,除了網(wǎng)絡(luò)不穩(wěn)定、網(wǎng)速過慢等原因,大多數(shù)都是由于頁面設(shè)計不合理導(dǎo)致加載時間過長導(dǎo)致的。

          我們都知道,頁面是用 HTML/CSS/JavaScript 來編寫的。

          • HTML 的職責(zé)在于告知瀏覽器如何組織頁面,以及搭建頁面的基本結(jié)構(gòu);
          • CSS 用來裝飾 HTML,讓我們的頁面更好看;
          • JavaScript 則可以豐富頁面功能,使靜態(tài)頁面動起來。

          HTML由一系列的元素組成,通常稱為HTML元素。HTML 元素通常被用來定義一個網(wǎng)頁結(jié)構(gòu),基本上所有網(wǎng)頁都是這樣的 HTML 結(jié)構(gòu):

          <html>
              <head></head>
              <body></body>
          </html>

          其中:

          • html元素是頁面的根元素,它描述完整的網(wǎng)頁;
          • head元素包含了我們想包含在 HTML 頁面中,但不希望顯示在網(wǎng)頁里的內(nèi)容;
          • body元素包含了我們訪問頁面時所有顯示在頁面上的內(nèi)容,是用戶最終能看到的內(nèi)容;


          HTML 中的元素特別多,其中還包括可用于 Web Components 的自定義元素。

          前面我們提到頁面 HTML 結(jié)構(gòu)不合理可能會導(dǎo)致頁面響應(yīng)慢,這個過程很多時候體現(xiàn)在<script><style>元素的設(shè)計上,它們會影響頁面加載過程中對 Javascript 和 CSS 代碼的處理。

          因此,如果想要提升頁面的加載速度,就需要了解瀏覽器頁面的加載過程是怎樣的,從根本上來解決問題。

          瀏覽器在加載頁面的時候會用到 GUI 渲染線程和 JavaScript 引擎線程(更詳細(xì)的瀏覽器加載和渲染機制將在第 7 講中介紹)。其中,GUI 渲染線程負(fù)責(zé)渲染瀏覽器界面 HTML 元素,JavaScript 引擎線程主要負(fù)責(zé)處理 JavaScript 腳本程序。

          由于 JavaScript 在執(zhí)行過程中還可能會改動界面結(jié)構(gòu)和樣式,因此它們之間被設(shè)計為互斥的關(guān)系。也就是說,當(dāng) JavaScript 引擎執(zhí)行時,GUI 線程會被掛起。

          以網(wǎng)易云課堂官網(wǎng)為例,我們來看看網(wǎng)頁加載流程。

          (1)當(dāng)我們打開官網(wǎng)的時候,瀏覽器會從服務(wù)器中獲取到 HTML 內(nèi)容。

          (2)瀏覽器獲取到 HTML 內(nèi)容后,就開始從上到下解析 HTML 的元素。

          (3)<head>元素內(nèi)容會先被解析,此時瀏覽器還沒開始渲染頁面。

          我們看到<head>元素里有用于描述頁面元數(shù)據(jù)的<meta>元素,還有一些<link>元素涉及外部資源(如圖片、CSS 樣式等),此時瀏覽器會去獲取這些外部資源。除此之外,我們還能看到<head>元素中還包含著不少的<script>元素,這些<script>元素通過src屬性指向外部資源。

          (4)當(dāng)瀏覽器解析到這里時(步驟 3),會暫停解析并下載 JavaScript 腳本。

          (5)當(dāng) JavaScript 腳本下載完成后,瀏覽器的控制權(quán)轉(zhuǎn)交給 JavaScript 引擎。當(dāng)腳本執(zhí)行完成后,控制權(quán)會交回給渲染引擎,渲染引擎繼續(xù)往下解析 HTML 頁面。

          (6)此時<body>元素內(nèi)容開始被解析,瀏覽器開始渲染頁面。

          在這個過程中,我們看到<head>中放置的<script>元素會阻塞頁面的渲染過程:把 JavaScript 放在<head>里,意味著必須把所有 JavaScript 代碼都下載、解析和解釋完成后,才能開始渲染頁面。

          到這里,我們就明白了:如果外部腳本加載時間很長(比如一直無法完成下載),就會造成網(wǎng)頁長時間失去響應(yīng),瀏覽器就會呈現(xiàn)“假死”狀態(tài),用戶體驗會變得很糟糕。

          因此,對于對性能要求較高、需要快速將內(nèi)容呈現(xiàn)給用戶的網(wǎng)頁,常常會將 JavaScript 腳本放在<body>的最后面。這樣可以避免資源阻塞,頁面得以迅速展示。我們還可以使用defer/async/preload等屬性來標(biāo)記<script>標(biāo)簽,來控制 JavaScript 的加載順序。

          百度首頁

          三、DOM 解析

          對于百度這樣的搜索引擎來說,必須要在最短的時間內(nèi)提供到可用的服務(wù)給用戶,其中就包括搜索框的顯示及可交互,除此之外的內(nèi)容優(yōu)先級會相對較低。

          瀏覽器在渲染頁面的過程需要解析 HTML、CSS 以得到 DOM 樹和 CSS 規(guī)則樹,它們結(jié)合后才生成最終的渲染樹并渲染。因此,我們還常常將 CSS 放在<head>里,可用來避免瀏覽器渲染的重復(fù)計算。


          二、HTML 與 DOM 有什么不同

          我們知道<p>是 HTML 元素,但又常常將<p>這樣一個元素稱為 DOM 節(jié)點,那么 HTML 和 DOM 到底有什么不一樣呢?

          根據(jù) MDN 官方描述:文檔對象模型(DOM)是 HTML 和 XML 文檔的編程接口。

          也就是說,DOM 是用來操作和描述 HTML 文檔的接口。如果說瀏覽器用 HTML 來描述網(wǎng)頁的結(jié)構(gòu)并渲染,那么使用 DOM 則可以獲取網(wǎng)頁的結(jié)構(gòu)并進(jìn)行操作。一般來說,我們使用 JavaScript 來操作 DOM 接口,從而實現(xiàn)頁面的動態(tài)變化,以及用戶的交互操作。

          在開發(fā)過程中,常常用對象的方式來描述某一類事物,用特定的結(jié)構(gòu)集合來描述某些事物的集合。DOM 也一樣,它將 HTML 文檔解析成一個由 DOM 節(jié)點以及包含屬性和方法的相關(guān)對象組成的結(jié)構(gòu)集合。


          三、DOM 解析

          我們常見的 HTML 元素,在瀏覽器中會被解析成節(jié)點。比如下面這樣的 HTML 內(nèi)容:

          <html>
              <head>
                  <title>標(biāo)題</title>
              </head>
              <body>
                  <a href='xx.com'>我的超鏈接</a>
                  <h1>頁面第一標(biāo)題</h1>
              </body>
          </html>

          打開控制臺 Elements 面板,可以看到這樣的 HTML 結(jié)構(gòu),如下圖所示:

          在瀏覽器中,上面的 HTML 會被解析成這樣的 DOM 樹,如下圖所示:


          我們都知道,對于樹狀結(jié)構(gòu)來說,常常使用parent/child/sibling等方式來描述各個節(jié)點之間的關(guān)系,對于 DOM 樹也不例外。

          舉個例子,我們常常會對頁面功能進(jìn)行抽象,并封裝成組件。但不管怎么進(jìn)行整理,頁面最終依然是基于 DOM 的樹狀結(jié)構(gòu),因此組件也是呈樹狀結(jié)構(gòu),組件間的關(guān)系也同樣可以使用parent/child/sibling這樣的方式來描述。同時,現(xiàn)在大多數(shù)應(yīng)用程序同樣以root為根節(jié)點展開,我們進(jìn)行狀態(tài)管理、數(shù)據(jù)管理也常常會呈現(xiàn)出樹狀結(jié)構(gòu)。


          四、事件委托

          我們知道,瀏覽器中各個元素從頁面中接收事件的順序包括事件捕獲階段、目標(biāo)階段、事件冒泡階段。其中,基于事件冒泡機制,我們可以實現(xiàn)將子元素的事件委托給父級元素來進(jìn)行處理,這便是事件委托。

          如果我們在每個元素上都進(jìn)行監(jiān)聽的話,則需要綁定三個事件;(假設(shè)頁面上有a,b,c三個兄弟節(jié)點)

          function clickEventFunction(e) {
            console.log(e.target === this); // logs `true`
            // 這里可以用 this 獲取當(dāng)前元素
          }
          // 元素a,b,c綁定
          element2.addEventListener("click", clickEventFunction, false);
          element5.addEventListener("click", clickEventFunction, false);
          element8.addEventListener("click", clickEventFunction, false);

          使用事件委托,可以通過將事件添加到它們的父節(jié)點,而將事件委托給父節(jié)點來觸發(fā)處理函數(shù):

          function clickEventFunction(event) {
            console.log(e.target === this); // logs `false`
            // 獲取被點擊的元素
            const eventTarget = event.target;
            // 檢查源元素`event.target`是否符合預(yù)期
            // 此處控制廣告面板的展示內(nèi)容
          }
          // 元素1綁定
          element1.addEventListener("click", clickEventFunction, false);

          這樣能解決什么問題呢?

          • 綁定子元素會綁定很多次的事件,而綁定父元素只需要一次綁定。
          • 將事件委托給父節(jié)點,這樣我們對子元素的增加和刪除、移動等,都不需要重新進(jìn)行事件綁定。

          常見的使用方式主要是上述這種列表結(jié)構(gòu),每個選項都可以進(jìn)行編輯、刪除、添加標(biāo)簽等功能,而把事件委托給父元素,不管我們新增、刪除、更新選項,都不需要手動去綁定和移除事件。

          如果在列表數(shù)量內(nèi)容較大的時候,對成千上萬節(jié)點進(jìn)行事件監(jiān)聽,也是不小的性能消耗。使用事件委托的方式,我們可以大量減少瀏覽器對元素的監(jiān)聽,也是在前端性能優(yōu)化中比較簡單和基礎(chǔ)的一個做法。

          注意:

          1. 如果我們直接在document.body上進(jìn)行事件委托,可能會帶來額外的問題;
          2. 由于瀏覽器在進(jìn)行頁面渲染的時候會有合成的步驟,合成的過程會先將頁面分成不同的合成層,而用戶與瀏覽器進(jìn)行交互的時候需要接收事件。此時,瀏覽器會將頁面上具有事件處理程序的區(qū)域進(jìn)行標(biāo)記,被標(biāo)記的區(qū)域會與主線程進(jìn)行通信。
          3. 如果我們document.body上被綁定了事件,這時候整個頁面都會被標(biāo)記;
          4. 即使我們的頁面不關(guān)心某些部分的用戶交互,合成器線程也必須與主線程進(jìn)行通信,并在每次事件發(fā)生時進(jìn)行等待。這種情況,我們可以使用passive: true選項來解決


          五、總結(jié)

          我們了解了 HTML 的作用,以及它是如何影響瀏覽器中頁面的加載過程的,同時還介紹了使用 DOM 接口來控制 HTML 的展示和功能邏輯。我們了解了DOM解析事件委托等相關(guān)概念。

          <!DOCTYPE html>
          <html>
          	<head>
          		<meta charset="utf-8">
          		<title>百度一下,你就知道</title>
          		<style type="text/css">
          			#img1{
          				position: relative;
          				left: 650px;
          			}
          			ul li{
          				float:left;
          				list-style: none;
          				padding: 5px;
          			}
          		a{
          			padding: 5px;
          			text-decoration:none;
          		}
          		
          		#baidu{
          			text-align: center;
          		}
          		#input1{
          			font-size: 30px;
          			width: 560px;
          		}
          		#db{
          			position:fixed; bottom:0;
          		}
          		#div1{
          			position: absolute;
          			bottom: 0;
          			right: 0;
          		}
          		#rebang{
          			font-size: 25px;
          			position: relative;
          			left: 610px;
          		}
          		
          		ul li div{
          			display: none;
          		}
          		ul li:hover div{
          			display: block;
          		}
          		#C{
          			font-size: 20px;
          			float: left;
          		}
          		#B{
          			position: absolute;
          			margin-left: 260px;
          			display: none;
          		}
          		#A{
          			font-size: 20px;
          			width: 1000px;
          		}
          		#A:hover #B{
          			display: block;
          		}
          		#D{
          			
          			font-size: 20px;
          			float: right;
          		}
          		#F{
          			position: absolute;
          			
          			display: none;
          		}
          		#D:hover #F{
          			display: block;
          		}
          		#G{
          			height: 50px;
          			
          			float: right;
          		}
          		#H{
          			background-color: blue;
          		}
          		#J{
          			position: absolute;
          			right: 800px;
          			top: 300px;
          			display: none;
          			z-index: 2;
          			
          		}
          		#G:hover #J{
          			display: block;
          			
          		}
          		#Z{
          			width: 100px;
          			height: 30px;
          		}
          		#W{
          			font-size: 22px;
          		}
          	</style>
          	</head>
          	<body>
          		<div id="C">
          			<a href="http://news.baidu.com/" target="_blank">新聞</a>
          			<a href="https://www.hao123.com/" target="_blank">hao123</a>
          			<a href="https://map.baidu.com/@12126927,4038819,13z/" target="_blank">地圖</a>
          			<a href="https://haokan.baidu.com/?sfrom=baidu-top/" target="_blank">視頻</a>
          			<a href="https://tieba.baidu.com/index.html/" target="_blank">貼吧</a>
          			<a href="https://xueshu.baidu.com//" target="_blank">學(xué)術(shù)</a>
          			</div>
          			<div id="A">
          			<a href="https://www.baidu.com/more//" target="_blank">更多</a>
          			<div id="B">
          				<ul>
          					<li><a href="https://pan.baidu.com/" target="_blank"><img src="imgs/wangpan.png"></img><br>網(wǎng)盤</a></li>
          				<li><a href="https://zhidao.baidu.com/" target="_blank"><img src="imgs/zhidao.png"></img><br>知道</a></li>
          				<li><a href="https://baike.baidu.com/" target="_blank"><img src="imgs/baike.png"></img><br>百科</a></li>
          				<li><a href="https://image.baidu.com/" target="_blank"><img src="imgs/tupian.png"></img><br>圖片</a></li>
          				</ul>
          				<ul>
          				<li><a href="https://baobao.baidu.com/" target="_blank"><img src="imgs/baobao.png"></img><br>寶寶</a></li>
          				<li><a href="https://wenku.baidu.com/" target="_blank"><img src="imgs/wenku.png"></img><br>文庫</a></li>
          				<li><a href="https://jingyan.baidu.com/" target="_blank"><img src="imgs/jingyan.png"></img><br>經(jīng)驗</a></li>
          				<li><a href="http://music.taihe.com/" target="_blank"><img src="imgs/yinyue.png"></img><br>音樂</a></li>
          				</ul>
          			</div>
          			</div>
          			<div id="G">
          			<a href="#"><input type="button"  value="登錄"></input></a>
          			<div id="J">
          				<img src="imgs/JJJ.png" >
          			</div>
          			</div>
          			<div id="D">
          				<a href="#">設(shè)置</a>
          				<div id="F">
          					<a href="#">搜索設(shè)置</a><br>
          					<a href="#">高級搜索</a><br>
          					<a href="#">關(guān)閉預(yù)測</a><br>
          					<a href="#">隱私設(shè)置</a><br>
          				</div>
          			</div>
          			
          		<div id="img1">
          		<img src="imgs/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png">
          		</div>
          		<div id="baidu">
          		<a href="#"><input id="input1" type="text" id="" value=""  /><input id="Z" type="button"  value="百度一下" /></a>
          		</div>
          		<div id="rebang">
          		<a href="http://top.baidu.com/?fr=mhd_card">百度熱榜</a>
          		</div>
          		<div id="resou" align="center">
          			<table id="W" border="0" cellspacing="5" cellpadding="25">
          				<tr>
          				<td><a href="https://www.baidu.com/s?cl=3&tn=baidutop10&fr=top1000&wd=%E7%89%B9%E6%9C%97%E6%99%AE%E7%A7%B0NBA%E5%83%8F%E4%B8%80%E4%B8%AA%E6%94%BF%E6%B2%BB%E7%BB%84%E7%BB%87&rsv_idx=2&rsv_dl=fyb_n_homepage&hisfilter=1">1.特朗普炮轟NBA</a></td>
          				<td><a href="https://www.baidu.com/s?cl=3&tn=baidutop10&fr=top1000&wd=%E5%AE%98%E6%96%B9%E8%B0%83%E6%9F%A5%E5%A5%B3%E6%95%99%E5%B8%88%E4%B8%BE%E6%8A%A5%E6%A0%A1%E9%95%BF%E6%80%A7%E9%AA%9A%E6%89%B0&rsv_idx=2&rsv_dl=fyb_n_homepage&hisfilter=1">4.官方調(diào)查女教師</a></td>
          				</tr>
          				<tr>
          				<td><a href="https://www.baidu.com/s?cl=3&tn=baidutop10&fr=top1000&wd=%E8%94%A1%E8%8E%89%E4%B8%8D%E5%86%8D%E6%8B%85%E4%BB%BB%E6%AD%A6%E6%B1%89%E5%B8%82%E4%B8%AD%E5%BF%83%E5%8C%BB%E9%99%A2%E4%B9%A6%E8%AE%B0&rsv_idx=2&rsv_dl=fyb_n_homepage&hisfilter=1">2.蔡麗不再擔(dān)任武漢市醫(yī)院書記</a></td>
          				<td><a href="https://www.baidu.com/s?cl=3&tn=baidutop10&fr=top1000&wd=%E9%99%88%E9%98%BF%E5%96%9C%E5%8E%BB%E4%B8%96&rsv_idx=2&rsv_dl=fyb_n_homepage&hisfilter=1">5.陳阿喜去世</a></td>
          				</tr>
          				<tr>
          				<td><a href="https://www.baidu.com/s?cl=3&tn=baidutop10&fr=top1000&wd=%E5%85%A8%E7%90%83%E8%BF%9110%E4%BA%BF%E4%BA%BA%E5%8F%97%E7%B2%BE%E7%A5%9E%E5%81%A5%E5%BA%B7%E9%97%AE%E9%A2%98%E5%BD%B1%E5%93%8D&rsv_idx=2&rsv_dl=fyb_n_homepage&hisfilter=1">3.全球近10億人受精神健康問題影響</a></td>
          				<td><a href="https://www.baidu.com/s?cl=3&tn=baidutop10&fr=top1000&wd=31%E7%9C%81%E5%8C%BA%E5%B8%82%E6%96%B0%E5%A2%9E%E5%A2%83%E5%A4%96%E8%BE%93%E5%85%A59%E4%BE%8B&rsv_idx=2&rsv_dl=fyb_n_homepage&hisfilter=1">6.31省區(qū)市新增境外輸入9例</a></td>
          				</tr>
          			</table>
          		</div>
          		<div id="db">
          			<ul>
          				<li>設(shè)為首頁</li>
          				<li>關(guān)于百度</li>
          				<li>About Baidu</li>
          				<li>百度營銷</li>
          				<li>使用百度前必讀</li>
          				<li>意見反饋</li>
          				<li>幫助中心</li>
          			</ul>
          		</div>
          		<div id="div1">
          			<ul>
          				
          			
          			<li>@2020 Baidu</li>
          			<li>(京)-經(jīng)營性-2017-0020</li>
          			<li>京公網(wǎng)安備11000002000001號</li>
          			<li>京ICP證030173號</li></ul>
          		</div>
          	</body>
          </html>
          

          上代碼寫出來的結(jié)果如下圖:


          新手勿噴!!!

          者公眾號:org_yijiaoqian

          HTTP1.0

          1.0的HTTP版本,是一種無狀態(tài),無連接的應(yīng)用層協(xié)議。 HTTP1.0規(guī)定瀏覽器和服務(wù)器保持短暫的鏈接。

          瀏覽器每次請求都需要與服務(wù)器建立一個TCP連接,服務(wù)器處理完成以后立即斷開TCP連接(無連接),服務(wù)器不跟蹤也每個客戶單,也不記錄過去的請求(無狀態(tài))。

          這種無狀態(tài)性可以借助cookie/session機制來做身份認(rèn)證和狀態(tài)記錄。

          HTTP1.0存在的問題

          無法復(fù)用連接

          每次發(fā)送請求,都需要進(jìn)行一次TCP連接,而TCP的連接釋放過程又是比較費事的。這種無連接的特性會使得網(wǎng)絡(luò)的利用率變低。

          隊頭阻塞(head of line blocking)

          由于HTTP1.0規(guī)定下一個請求必須在前一個請求響應(yīng)到達(dá)之前才能發(fā)送,假設(shè)前一個請求響應(yīng)一直不到達(dá),那么下一個請求就不發(fā)送,后面的請求就阻塞了。

          HTTP1.1

          HTTP1.1繼承了HTTP1.0的簡單,克服了HTTP1.0性能上的問題。

          長連接

          HTTP1.1增加Connection字段,通過設(shè)置Keep-Alive保持HTTP連接不斷卡。避免每次客戶端與服務(wù)器請求都要重復(fù)建立釋放建立TCP連接。提高了網(wǎng)絡(luò)的利用率。

          如果客戶端想關(guān)閉HTTP連接,可以在請求頭中攜帶Connection:false來告知服務(wù)器關(guān)閉請求。

          管道化(pipelining)— 尷尬的假并行傳輸

          HTTP1.1支持請求管道化(pipelining)。

          基于HTTP1.1的長連接,使得請求管線化成為可能。 管線化使得請求能夠“并行”傳輸。

          例如

          假如響應(yīng)的主體是一個html頁面,頁面中包含了很多img,這個時候keep-alive就了很大作用。能夠“并行”發(fā)送多個請求。(注意,這里的“并行”并不是真正意義上的并行傳輸

          需要注意的是:服務(wù)器必須按照客戶端請求的先后順序依次回送相應(yīng)的結(jié)果,以保證客戶端能夠區(qū)分出每次請求的響應(yīng)內(nèi)容。

          也就是說,HTTP管道化可以讓我們把先進(jìn)先出隊列從客戶端(請求隊列)遷移到服務(wù)端(響應(yīng)隊列)

          如果,客戶端同時發(fā)了兩個請求分別獲取html和css,假如說服務(wù)器的css資源先準(zhǔn)備就緒,服務(wù)器也會先發(fā)送html,再發(fā)送css。 換句話來說,只有等到html響應(yīng)的資源完全傳輸完畢后,css響應(yīng)的資源才開始傳輸,不允許同時存在兩個并行的響應(yīng)。

          可見,HTTP1.1還是無法解決隊頭阻塞(head of line blocking)的問題。同時“管道化”技術(shù)存在各種各樣的問題,所以很多瀏覽器要么根本不支持它,要么直接默認(rèn)關(guān)閉,并且開啟的條件很苛刻……而且好像實際也沒有什么用處。

          真并行傳輸 — 瀏覽器優(yōu)化策略

          HTTP1.1支持管道化,但是服務(wù)器也必須進(jìn)行逐個響應(yīng)的送回,這個是很大的一個缺陷。實際上,現(xiàn)階段的瀏覽器廠商采取了另外一種做法,它允許我們打開多個TCP的會話,也就是說,上圖我們看到的并行,其實是不同的TCP連接上的HTTP請求和相應(yīng)。這才是真正的并行!

          很多人以為的連接數(shù)情況:


          實際情況(china):


          緩存處理 — 強緩存、協(xié)商緩存,啟發(fā)式緩存(新增)

          此外,HTTP1.1還加入了緩存處理(強緩存和協(xié)商緩存),新的字段如cache-control,支持?jǐn)帱c傳輸,以及增加了Host字段(使得一個服務(wù)器能夠用來創(chuàng)建多個Web站點)

          HTTP2.0

          二進(jìn)制分幀

          HTTP2.0通過在應(yīng)用層和傳輸層之間增加一個二進(jìn)制分層幀,突破了HTTP1.1的性能限制,改進(jìn)傳輸性能。

          多路復(fù)用(鏈接共享)— 真并行傳輸

          • 流(stream):已建立連接上的雙向字節(jié)流。
          • 消息:與邏輯消息對應(yīng)的完整的一系列數(shù)據(jù)幀。
          • 幀(frame):HTTP2.0通信的最小單位,每個幀包含頭部,至少也會標(biāo)識出當(dāng)前所屬的流(stream_id)

          所有HTTP2.0通信都在一個TCP鏈接上完成,這個鏈接可以承載任意流量的雙向數(shù)據(jù)流。

          每個數(shù)據(jù)流以消息的形式發(fā)送,而消息由一或多個幀組成。這些幀可以亂序發(fā)送,然后再根據(jù)每個幀頭部的流標(biāo)識符(Stream_id)重新封裝。

          多路復(fù)用(連接共享)可能會導(dǎo)致關(guān)鍵字被阻塞,HTTP2.0里每個數(shù)據(jù)流都可以設(shè)置優(yōu)先級和依賴,優(yōu)先級高的數(shù)據(jù)流會被服務(wù)器優(yōu)先處理和返回客戶端,數(shù)據(jù)流還可以依賴其他的子數(shù)據(jù)流。

          可見,HTTP2.0實現(xiàn)了真正的并行傳輸,它能夠在一個TCP上進(jìn)行任意數(shù)量的HTTP請求。而這個強大的功能基于“二級制分幀”的特性。

          頭部壓縮

          在HTTP1.X中,頭部元數(shù)據(jù)都是以純文本的形式發(fā)送的,通常會給每個請求增加500-8000字節(jié)的負(fù)荷。

          比如cookie,默認(rèn)情況下,瀏覽器會在每次請求的時候,把cookie附在header上面發(fā)給服務(wù)器。

          HTTP2.0使用encoder來減少需要傳輸?shù)膆eader大小,通訊雙方各自cache一份header_files表,既避免重復(fù)header的傳輸,又減少了需要傳輸?shù)拇笮 ?/span>

          高效的壓縮算法可以很大的壓縮header,減少發(fā)送包的數(shù)量從而降低延遲。

          服務(wù)器推送

          服務(wù)器除了最初請求的響應(yīng)外,服務(wù)器還可以額外向客戶端推送資源,而無需客戶端明確的需求。

          HTTP3.0

          Google搞了一個基于UDP協(xié)議的QUIC協(xié)議,并且使用在了HTTP/3上, HTTP/3之前的名稱為HTTP-over-QUIC。

          早期Quic協(xié)議,存在IETF和Google兩個版本,直到它被證實命名為HTTP3.0

          IETF的QUIC工作小組創(chuàng)造了QUIC傳輸協(xié)議。QUIC是一個使用UDP來替代TCP的協(xié)議。最初的時候,Google開始助力QUIC,其后QUIC更多地被叫做“HTTP/2-encrypted-over-UDP “。

          社區(qū)中的人們已經(jīng)使用非正式名稱如iQUIC和gQUIC來指代這些不同版本的協(xié)議,以將QUIC協(xié)議與IETF和Google分開(因為它們在細(xì)節(jié)上差異很大)。通過“iQUIC”發(fā)送HTTP的協(xié)議被稱為“HQ”(HTTP-over-QUIC)很長一段時間。

          2018年11月7日,Litespeed的Dmitri宣布他們和Facebook已經(jīng)成功地完成了兩個HTTP/3實現(xiàn)之間的第一次互操作。Mike Bihop在該主題的HTTPBIS會話中的后續(xù)介紹可以在這里看到。會議結(jié)束時達(dá)成共識稱新名稱是HTTP/3!

          0-RTT — QUIC協(xié)議相比HTTP2.0的最大優(yōu)勢

          緩存當(dāng)前會話的上下文,下次恢復(fù)會話的時候,只需要將之前的緩存?zhèn)鬟f給服務(wù)器,驗證通過,就可以進(jìn)行傳輸了。

          0-RTT建連可以說是QUIC相比HTTP2最大的性能優(yōu)勢。

          什么是0-RTT建連

          • 傳輸層0-RTT就能建立連接
          • 加密層0-RTT就能建立加密連接

          多路復(fù)用

          QUIC基于UDP,一個連接上的多個stream之間沒有依賴,即使丟包,只需要重發(fā)丟失的包即可,不需要重傳整個連接。

          更好的移動端表現(xiàn)

          QUIC在移動端的表現(xiàn)比TCP好,因為TCP是基于IP識別連接,而QUIC是通過ID識別鏈接。 無論網(wǎng)絡(luò)環(huán)境如何變化,只要ID不便,就能迅速重新連上。

          加密認(rèn)證的根文 — 武裝到牙齒

          TCP協(xié)議頭沒有經(jīng)過任何加密和認(rèn)證,在傳輸過程中很容易被中間網(wǎng)絡(luò)設(shè)備篡改、注入和竊聽。

          QUIC的packet可以說武裝到了牙齒,除了個別報文,比如PUBLIC_RESET和CHLO,所有報文頭部都是經(jīng)過認(rèn)證的,報文Body都是經(jīng)過加密的。

          所以只要對 QUIC 做任何更改,接收端都能及時發(fā)現(xiàn),有效地降低了安全風(fēng)險。

          向前糾錯機制

          QUIC協(xié)議有一個非常獨特的特性,稱為向前糾錯(Foward Error Connec,F(xiàn)EC),每個數(shù)據(jù)包除了它本身的內(nèi)容之外還包括了其他數(shù)據(jù)包的數(shù)據(jù),因此少量的丟包可以通過其他包的冗余數(shù)據(jù)直接組裝而無需重傳。

          向前糾錯犧牲了每個數(shù)據(jù)包可以發(fā)送數(shù)據(jù)的上限,但是帶來的提升大于丟包導(dǎo)致的數(shù)據(jù)重傳,因為數(shù)據(jù)重傳將會消耗更多的時間(包括確認(rèn)數(shù)據(jù)包丟失,請求重傳,等待新數(shù)據(jù)包等步驟的時間消耗)。

          例如:

          • 我總共發(fā)送三個包,協(xié)議會算出這個三個包的異或值并單獨發(fā)出一個校驗包,也就是總共發(fā)出了四個包。
          • 當(dāng)其中出現(xiàn)了非校驗包丟失的情況,可以通過另外三個包計算出丟失的數(shù)據(jù)包的內(nèi)容。
          • 當(dāng)然這種技術(shù)只能使用在丟失一個包的情況下,如果出現(xiàn)丟失多個包,就不能使用糾錯機制了,只能使用重傳的方式了。

          問題歸納

          HTTP1.1的合并請求(如CSSsprites)是否適用于HTTP2.0

          沒有必要。

          在頭部壓縮技術(shù)中,客戶端和服務(wù)器均會維護(hù)兩份相同的靜態(tài)字典動態(tài)字典

          在靜態(tài)字典中,包含了常見的頭部名稱與值的組合。靜態(tài)字典在首次請求時可以使用。那么現(xiàn)在頭部的字段就可以被簡寫成靜態(tài)字典中相應(yīng)字段的index。

          而動態(tài)字典跟連接的上下文相關(guān),每個HTTP/2連接維護(hù)的動態(tài)字典不盡相同。動態(tài)字典可以在連接不停地進(jìn)行更新。

          也就是說,原本完整的HTTP報文頭部的鍵值或字段,由于字典的存在,現(xiàn)在可以轉(zhuǎn)換成索引index,在相應(yīng)的端再進(jìn)行查找還原,也就起到了壓縮的作用。

          所以,同一個鏈接上產(chǎn)生的請求和響應(yīng)越多,動態(tài)字典累積得越全,頭部壓縮的效果也就越好,所以針對HTTP/2網(wǎng)站,最佳實踐是不要合并資源

          另外,HTTP2.0多路復(fù)用,使得請求可以并行傳輸,而HTTP1.1合并請求的一個原因也是為了防止過多的HTTP請求帶來的阻塞問題。而現(xiàn)在HTTP2.0已經(jīng)能夠并行傳輸了,所以合并請求也就沒有必要了。

          為什么要有HTTP3.0:HTTP/2底層TCP的局限帶來的問題

          由于HTTP/2使用了多路復(fù)用,一般來說,同一個域名下只需要使用一個TCP鏈接,但當(dāng)這個連接中出現(xiàn)了丟包的情況,就會導(dǎo)致HTTP/2的表現(xiàn)情況反倒不如HTTP/2了。

          原因是: 在出現(xiàn)丟包的額情況下,整個TCP都要開始等待重傳,導(dǎo)致后面的所有數(shù)據(jù)都被阻塞。

          但是對于HTTP/1.1來說,可以開啟多個TCP連接,出現(xiàn)這種情況只會影響其中一個連接,剩余的TCP鏈接還可以正常傳輸數(shù)據(jù)。

          由于修改TCP協(xié)議是不可能完成的任務(wù)。

          如何在Chrome中啟用 QUIC 協(xié)議

          MTF在資源服務(wù)器和內(nèi)容分發(fā)節(jié)點都已經(jīng)啟用了 HTTP3.0 協(xié)議,根據(jù) 用戶瀏覽器 向下兼容,強烈建議您在Chrome瀏覽器開啟實驗性QUICK協(xié)議支持,體驗加速效果:

          1. 在瀏覽器地址欄:輸入chrome://flags
          2. 找到Experimental QUIC protocol,將Default改為Enabled


          總結(jié)

          HTTP 1.0

          • 無狀態(tài),無連接
          • 短連接:每次發(fā)送請求都要重新建立tcp請求,即三次握手,非常浪費性能
          • 無host頭域,也就是http請求頭里的host,
          • 不允許斷點續(xù)傳,而且不能只傳輸對象的一部分,要求傳輸整個對象


          HTTP 1.1

          • 長連接,流水線,使用connection:keep-alive使用長連接
          • 請求管道化
          • 增加緩存處理(新的字段如cache-control)
          • 增加Host字段,支持?jǐn)帱c傳輸?shù)?/li>
          • 由于長連接會給服務(wù)器造成壓力


          HTTP 2.0

          • 二進(jìn)制分幀
          • 頭部壓縮,雙方各自維護(hù)一個header的索引表,使得不需要直接發(fā)送值,通過發(fā)送key縮減頭部大小
          • 多路復(fù)用(或連接共享),使用多個stream,每個stream又分幀傳輸,使得一個tcp連接能夠處理多個http請求
          • 服務(wù)器推送(Sever push)


          HTTP 3.0

          • 基于google的QUIC協(xié)議,而quic協(xié)議是使用udp實現(xiàn)的
          • 減少了tcp三次握手時間,以及tls握手時間
          • 解決了http 2.0中前一個stream丟包導(dǎo)致后一個stream被阻塞的問題
          • 優(yōu)化了重傳策略,重傳包和原包的編號不同,降低后續(xù)重傳計算的消耗
          • 連接遷移,不再用tcp四元組確定一個連接,而是用一個64位隨機數(shù)來確定這個連接
          • 更合適的流量控制

          基于UDP實現(xiàn)

          0RTT建連

          基于UDP的多路復(fù)用

          加密認(rèn)證的報文

          向前糾錯機制

          文章持續(xù)更新,可以公眾號搜一搜「 一角錢技術(shù) 」第一時間閱讀, 本文 GitHub org_hejianhui/JavaStudy 已經(jīng)收錄,歡迎 Star。


          主站蜘蛛池模板: 五十路熟女人妻一区二区| 国模无码视频一区| 麻豆国产一区二区在线观看| 日韩精品一区二区三区毛片| 国产色综合一区二区三区| 精品国产亚洲第一区二区三区| 久久一区不卡中文字幕| 在线精品国产一区二区三区| 色精品一区二区三区| 国产福利电影一区二区三区,日韩伦理电影在线福 | 中文字幕日韩欧美一区二区三区| 在线观看国产区亚洲一区成人 | 亚洲一区二区无码偷拍| 日产精品久久久一区二区| 中日av乱码一区二区三区乱码| 人妻无码一区二区三区四区| 国产成人一区二区三区电影网站| 国产成人欧美一区二区三区 | 精品国产毛片一区二区无码 | 久久久国产精品亚洲一区 | 无码人妻一区二区三区在线视频 | 国产成人精品一区二区三在线观看 | 亚洲日韩AV无码一区二区三区人| 日韩精品一区二区三区色欲AV| 国产婷婷色一区二区三区| 精品国产免费一区二区三区香蕉 | 精彩视频一区二区三区| 精品国产精品久久一区免费式 | 国产视频一区在线观看| 亚洲国产成人久久综合一区77| 日韩视频一区二区| 精品国产一区二区三区www| 日本在线电影一区二区三区| 免费在线视频一区| 午夜福利国产一区二区| 久久精品国产免费一区| 亚洲一区电影在线观看| 国产成人精品视频一区| 少妇人妻偷人精品一区二区| 秋霞午夜一区二区| 伊人色综合一区二区三区影院视频|