## **多路復用**
在HTTP/2中,有兩個非常重要的概念:幀(frame)和流(stream)。
**1、幀(frame)**
HTTP/2中數據傳輸的最小單位,因此幀不僅要細分表達HTTP/1.x中的各個部份,也優化了HTTP/1.x表達得不好的地方,同時還增加了HTTP/1.x表達不了的方式。
每一幀都包含幾個字段,有length、type、flags、stream identifier、frame playload等,其中type代表幀的類型,在HTTP/2的標準中定義了10種不同的類型,包括上面所說的`HEADERS` frame和 `DATA` frame。此外還有
`PRIORITY`(設置流的優先級)
`RST_STREAM`(終止流)
`SETTINGS`(設置此連接的參數)
`PUSH_PROMISE`(服務器推送)
`PING`(測量RTT)
`GOAWAY`(終止連接)
`WINDOW_UPDATE`(流量控制)
`CONTINUATION`(繼續傳輸頭部數據)
**2、流(stream)**
“流”在HTTP/2中是一個邏輯上的概念,就是說在一個TCP連接上,我們可以向對方不斷發送一個個的消息,這里每一個消息看成是一幀,而每一幀有個stream identifier的字段標明這一幀屬于哪個“流”,然后在對方接收時,根據stream identifier拼接每個“流”的所有幀組成一整塊數據。我們把HTTP/1.x每個請求都當作一個“流”,那么請求化成多個流,請求響應數據切成多個幀,不同流中的幀交錯地發送給對方,這就是HTTP/2中的多路復用。

從上圖我們可以留意到:
* 不同的流在交錯發送;
* `HEADERS` 幀在 `DATA` 幀前面;
* 流的ID都是奇數,說明是由客戶端發起的,這是標準規定的,那么服務端發起的就是偶數了。
多路復用讓HTTP連接變得很廉價,只需要創建一個新流即可,這不需要多少時間,而在HTTP/1.x時代卻要經歷三次握手時間或者隊首阻塞等問題。而且創建新流默認是無限制的,也就是可以無限制的并行請求下載。不過,HTTP/2還是提供了 `SETTINGS_MAX_CONCURRENT_STREAMS` 字段在 `SETTINGS` 幀上設置,可以限制并發流數目,標準上建議不要低于100以保證性能。
優化Web性能有一個常用的技術,就是圖片延遲加載,目的是除了節省流量外,還能避免圖片資源與其他重要的腳本資源競爭下載。
HTTP/2提供了流的優先級與依賴性這種機制,可用 `HEADERS` 幀或 `PRIORITY` 幀設置,不過協議并沒有提供如何處理優先級的具體算法,這可由服務器靈活應對。我用個例子來說明這個機制。
~~~
<!-- a.html -->
<html>
<body>
<script src="a.js"></script>
<img src="a.jpg">
<img src="b.jpg">
<link rel="stylesheet" type="text/css" href="style.css">
</body>
</html>
~~~
瀏覽器是邊下載邊解析的,文檔解析器首先遇到a.js,它就會去下載并且阻塞頁面,同時,資源探測器會繼續向下掃描,發現a.jpg、b.jpg和style.css并服務器發起請求。在沒有優先級機制時,a.jpg、b.jpg會跟重要的a.js、style.css競爭下載,但在HTTP/2中,瀏覽器可以給a.jpg、b.jpg設置較低的優先級,另外依賴關系為

這樣服務器根據優先級信息,首先吐出a.js、style.css,再吐出圖片,因此頁面在沒有圖片的情況下提前進入可交互狀態。例子所說的是在瀏覽器層面上harcode的一個優先級策略,再比如上文提到的prefetch就可以給一個更低的優先級。在代碼層面上,也許之后會提供一些控制優先級的特性,類似于目前只有IE支持的lazyload attribute。