script-streaming 是什么?
加載 JavaScript 算是 web 性能最嚴(yán)重的瓶頸之一,尤其在低端 CPU 上情況更糟糕。加載 JavaScript 的性能損耗不僅包括從服務(wù)器上下載數(shù)據(jù)的網(wǎng)絡(luò)時(shí)間,也包括文件解壓、解析、編譯,以及執(zhí)行 JavaScript 的時(shí)間。為了更好的用戶體驗(yàn),web 頁面大量的 JavaScript 代碼數(shù)量持續(xù)地增長,頁面加載變得越來越慢。瀏覽器社區(qū)一直在開發(fā)很多優(yōu)化措施來提升 JavaScript 加載速度,比如將解析 JavaScript 文件和下載過程并行化(在此之前,瀏覽器會(huì)等待 JavaScript 文件完全下載后才會(huì)在渲染主線程上進(jìn)行解析)。這項(xiàng)優(yōu)化措施就是 script-streaming,它在 Chrome v41 上被引入。Google 聲稱 script-streaming 能夠?qū)㈨撁婕虞d速度提升 10%,因?yàn)榇笮?JavaScript 文件會(huì)邊下載邊解析,這可以減少數(shù)百毫秒的頁面加載時(shí)間。
Script-streaming 是為加速 JavaScript 解析而做的一項(xiàng)巨大的優(yōu)化。然而,Chrome 針對 JavaScript 文件啟用 script-streaming 還有一些限制。
首先,下載的 JavaScript 文件大小至少 30KB。這個(gè)尺寸限制確保了只有大型 JS 文件能夠通過 script-streaming 解析,因?yàn)橄啾扔谳^小的 JavaScript 文件,并行下載和解析大型 JavaScript 文件的收益最大。
其次,目前 Chrome 在 script-streaming 的實(shí)現(xiàn)上,同一時(shí)刻 script-streaming 只能應(yīng)用到一個(gè) JavaScript 文件上。這是由于 Chrome 對于 script-streaming 只使用了單線程。既然這個(gè)線程忙于解析某個(gè) JavaScript 文件,那么其他 JavaScript 文件就必須在主線程下載完成后,才能進(jìn)行解析。
web 開發(fā)者如何利用 script-streaming ?
script-streaming 加速了 JavaScript 的解析。作為一個(gè) web 開發(fā)者,你不必為了在頁面上啟用 script-streaming 做任何事情。然而,script-streaming 還是有一些限制的,這些限制只存在于 Chrome,它們是由于 Chrome 的實(shí)現(xiàn)造成的。具體來說,當(dāng)大型 JavaScript 文件下載完成,script-streaming 線程不保證一定可用。同樣地,頁面并行下載多個(gè)大型 JavaScript 文件,只有一個(gè)文件能夠通過 script-streaming 解析。并且,某些情況下,script-streaming 可能解析較小的腳本文件,而較大的腳本只能等待 script-streaming 線程可用,或者在完成下載后,由主線程進(jìn)行解析。
開發(fā)者可以使用 performance 開發(fā)者工具來研究 script-streaming 是否被用于解析大型 JavaScript 文件,因?yàn)檫@項(xiàng)技術(shù)可以顯著提升頁面性能。下圖是 www.akamai.com 在 performance 面板上的一個(gè)截圖,腳本就是被紅框里的 ScriptStreamer 線程解析的。
[圖片上傳失敗...(image-229024-1538213191690)]
提升解析速度的兩種方法
我做了一些研究,為了啟用 script-streaming,可以解析較小的 JavaScript 文件(仍然大于 30KB),這樣在解析相對較大的 JavaScript 文件時(shí),保持線程是可用的。理論上,可以在大型 JavaScript 文件上發(fā)送一個(gè) HTTP 響應(yīng)頭,告訴瀏覽器在具有這種響應(yīng)頭的文件上應(yīng)用 script-streaming。然而,這個(gè)方法要求主流瀏覽器作出調(diào)整,并且能讓 script-streaming 利用多線程,而不僅僅是單線程。值得注意的是,目前 使用多個(gè) script-streaming 線程在 Chrome 團(tuán)隊(duì)內(nèi)部依然是 TODO 狀態(tài)。
一個(gè)比較實(shí)用的,執(zhí)行起來簡單得多,并且不需要瀏覽器改變的技巧,是重新排序 HTML 中那些加載靜態(tài)資源 URL 的 <script> 標(biāo)簽的位置,以讓大的 JavaScript 文件在較小(仍然大于 30KB)文件之前下載。當(dāng) script-streaming 可用時(shí),此方法會(huì)強(qiáng)制解析大型 JavaScript 文件。重新排序 <script> 標(biāo)簽在 HTML 中的位置,可能存在潛在風(fēng)險(xiǎn)。因?yàn)闉榱吮3猪撁娴墓δ芎?UI,一些 JavaScript 必須按順序執(zhí)行。因此,在重新排序時(shí)必須要謹(jǐn)慎。重新排序那些帶上=有 async 或者 defer 屬性的 <script> 標(biāo)簽會(huì)保險(xiǎn)一些,因?yàn)檫@些腳本執(zhí)行并不依賴于執(zhí)行順序。由于腳本重排序伴隨著種種限制,這項(xiàng)實(shí)驗(yàn)性的方法將只在指定的網(wǎng)站上生效。除了腳本重排序之外,我加進(jìn)來的另一個(gè)方法是,將多個(gè)大型 JavaScript 文件并行下載,讓它們競爭 script-streaming 線程。我將所有這樣的 JavaScript 文件串聯(lián)起來,目的是讓他們都可以實(shí)現(xiàn)邊下載邊解析。
實(shí)驗(yàn)結(jié)果
我做了一些實(shí)驗(yàn),去衡量上述兩個(gè)方法在多個(gè)設(shè)備上的頁面加載時(shí)間,包括 MacBook Pro,一個(gè)低端移動(dòng)設(shè)備(Motorola Moto E),和一個(gè)高端移動(dòng)設(shè)備(Motorola Moto G)。性能數(shù)據(jù)通過一個(gè)私有網(wǎng)頁測試實(shí)例.收集。在兩個(gè)手動(dòng)修改的網(wǎng)站(“Page A” 和 “Page B”,詳情見下表)集合上,觀察到在多個(gè)移動(dòng)設(shè)備和 MacBook Pro 上,對于中等規(guī)模的頁面有多達(dá) 6.2% 的頁面加載時(shí)間提升。這些性能提升要?dú)w功于 JavaScript 解析和下載的并行化。
| Page | \資源數(shù) | 頁面大小 | #JavaScript 資源數(shù) | ** JavaScript 總大小** |
|---|---|---|---|---|
| A | 41 | 2.7 MB | 12 | 1.3 MB |
| B | 95 | 2.2 MB | 19 | 1.1 MB |
MacBook Pro 上的性能
圖 1 和圖 2 展示了在一臺(tái) MacBook Pro 上,兩個(gè)測試頁面加載時(shí)間的 CDF 分布。頁面 A 上,重新排序 script 標(biāo)簽在 HTML 中的位置的頁面加載時(shí)間減少了 6.2%。頁面 B 上,加載重新排序的 scrip 標(biāo)簽的頁面加載時(shí)間減少了 4.5%。
[圖片上傳失敗...(image-cc044e-1538213191690)]
Motorola Moto E 上的性能
正如下圖所示,重排序 script 標(biāo)簽的頁面 A 的加載時(shí)間減少了 4.3%。
頁面 B(沒有示例圖)上沒有出現(xiàn)更快的加載速度,這可能是因?yàn)樵?Moto E 設(shè)備上,當(dāng)移動(dòng)版頁面 A 加載時(shí), script-streaming 線程被占用了。
[圖片上傳失敗...(image-dccbb4-1538213191690)]
Motorola Moto G 上的性能
如下圖所示,重排序 script 標(biāo)簽的頁面 A 的加載時(shí)間減少了 3.5%。
頁面 B 上,中等規(guī)模頁面的加載時(shí)間減少了 1.9%。
[圖片上傳失敗...(image-bf44d5-1538213191690)]
總結(jié)
本文描述的實(shí)驗(yàn)性工作舉例說明了相比默認(rèn)的解析,通過 script-streaming 解析較大 JavaScript 文件帶來的好處。實(shí)驗(yàn)包含重排序 HTML 中的 <script> 標(biāo)簽,以及串聯(lián)多個(gè)大型 JavaScript 文件,讓它們并行下載,以允許相對較大的文件能夠通過 script-streaming 解析。實(shí)驗(yàn)結(jié)果顯示,在 MacBook Pro 和兩個(gè)低端和高端的移動(dòng)設(shè)備上,對于中等大小的頁面,加載速度有多達(dá) 6% 的提升。
原文作者: Utkarsh Goel
譯者: 熊賢仁