中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

不簡單的前端性能優(yōu)化

2018-07-20    來源:編程學(xué)習(xí)網(wǎng)

容器云強(qiáng)勢上線!快速搭建集群,上萬Linux鏡像隨意使用

本文主要介紹“關(guān)鍵渲染路徑”與“網(wǎng)絡(luò)”兩個(gè)方面的性能優(yōu)化并提供demo,篇幅較長建議電腦觀看。

前端優(yōu)化的方面太多,本文介紹的僅僅是其中的一部分,力求涵蓋“關(guān)鍵渲染路徑”的方方面面,及一些不常被提到的“網(wǎng)絡(luò)優(yōu)化”部分。

測試環(huán)境如無特殊說明均為Chrome 57

渲染頁面過程

瀏覽器從打開一個(gè)URL到渲染完頁面共有:

  • 下載HTML文檔

  • 下載HTML文檔中的css

  • 下載Js文件

  • 執(zhí)行js腳本

  • 下載其他資源

  • 通過HTML文檔構(gòu)建DOM(Parse HTML)

  • 通過CSS文件構(gòu)建CSSOM(Parse CSS)

  • 通過DOM與CSSOM計(jì)算render tree

  • 根據(jù)render tree進(jìn)行繪制,計(jì)算各個(gè)元素位置與大小(Layout)

  • 對頁面進(jìn)行上色,渲染為最終顯示的像素(Paint)

第一次完成Paint稱為“初次渲染”,這時(shí)候用戶就能看到render tree里面的東西了。而完成初次渲染的過程稱為“關(guān)鍵渲染路徑”,關(guān)鍵渲染路徑上需要加載的資源叫做“關(guān)鍵資源”

這個(gè)過程很多很復(fù)雜,其中的依賴關(guān)系也很復(fù)雜,筆者嘗試畫圖來表示,但是實(shí)在是沒畫出來,所以還是用文字來表述吧:

  • 引入的資源,哪怕被阻塞(比如被js腳本阻塞后續(xù)link標(biāo)簽),瀏覽器依舊會智能的預(yù)先加載它們(但是不執(zhí)行)

  • “CSS文件的加載”會阻塞“Js文件執(zhí)行”。若CSS引用在Js文件之前,“加載CSS文件”會阻塞“Js文件執(zhí)行”。即CSS文件未加載解析完成前,js文件不會得到執(zhí)行。因?yàn)閖s有可能會修改CSSOM。帶有async和defer屬性的script不受限制。

  • Parse HTML的解析是增量的,因此瀏覽器可以邊下載HTML邊構(gòu)建DOM樹

  • “CSS文件的加載”會阻塞“Layout”。若頁面有正在加載的CSS文件,在CSS文件加載完之前,瀏覽器不會對頁面進(jìn)行Layout,這是為了防止樣式突變帶來的抖動

  • “加載Js文件”會阻塞“Parse HTML”,這個(gè)估計(jì)大家都知道了,因?yàn)閖s可以通過document.write修改HTML文檔流

  • “Js文件執(zhí)行”會幾乎會阻塞所有東西,包括Layout

比較有意思的是,字體的加載會阻塞局部的渲染。若某一段文本的字體使用了一個(gè)尚未加載完的字體,這段文本則先不會被Paint,直到字體加載完或者超過某個(gè)時(shí)間(通常是3秒)文本才會突然顯示。

瀏覽器為了避免FOUT(Flash Of Unstyled Text),會 盡量 等待字體加載完成后,再顯示應(yīng)用了該字體的內(nèi)容。只有當(dāng)字體超過一段時(shí)間仍未加載成功時(shí),瀏覽器才會降級使用系統(tǒng)字體。每個(gè)瀏覽器都規(guī)定了自己的超時(shí)時(shí)間(Chrome是3秒)。但這也帶來了FOIT(Flash Of Invisible Text)問題。內(nèi)容無法盡快地被展示,導(dǎo)致空白

一些Demo來解釋瀏覽器渲染流程

CSS會阻塞Layout: 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="style.css" />
    <!-- 這個(gè)css文件會加載3秒鐘,在這個(gè)css加載完成前瀏覽器不會layout -->
    <link rel="stylesheet" href="../conn/sleep.php?sleep=3&content=h2{color:red;}" />
    <title>Title</title>
</head>
<body>
    <h1>Hello</h1>
    <h2>World</h2>
</body>
</html>

CSS會阻塞Js執(zhí)行: 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="style.css" />
    <!-- 這個(gè)css文件會加載3秒鐘 -->
    <link rel="stylesheet" href="../conn/sleep.php?sleep=3&content=h2{color:red;}" />
    <script>
        // 這段js會等待css加載完才會運(yùn)行
        alert('js is run!');
    </script>
    <title>Title</title>
</head>
<body>
    <h1>Hello</h1>
    <h2>World</h2>
</body>
</html>

Js執(zhí)行會阻塞關(guān)鍵渲染路徑,哪怕是defer還是async: 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script>
        function sleep(ms){
            var ts =+new Date;
            while(true){
                if(+new Date -ts >=ms) break;
            }
            return +new Date -ts;
        }
    </script>
    <!-- 這個(gè)css文件會加載2秒鐘,所以會在js文件之后加載完 -->
    <link rel="stylesheet" href="../conn/sleep.php?sleep=2&content=h2{color:red;}" />
    <!-- 這個(gè)js文件會瞬間加載完,但是會運(yùn)行3秒鐘 -->
    <script defer src="run3s.js"></script>
    <!-- 這個(gè)js文件會瞬間加載完,但是會運(yùn)行2秒鐘 -->
    <script async src="run2s.js"></script>
    <title>Title</title>
</head>
<body>
    <!-- 打開頁面后5秒鐘才會顯示,因?yàn)閖s執(zhí)行會阻塞關(guān)鍵渲染路徑 -->
    <h1>Hello</h1>
    <h2>World</h2>
</body>
</html>

Foot會阻塞局部渲染,但是智能的瀏覽器會給他設(shè)定一個(gè)上限,一般是3秒鐘: 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <style>
        @font-face {
            font-family: "test-font";
            src: url("../conn/sleep.php?sleep=5&file=scripts_.ttf");
        }
        h1{
            font-family: "test-font";
        }
    </style>
    <title>Title</title>
</head>
<body>
    <h1>Hello</h1>
    <h2>World</h2>
</body>
</html>

CSS篇優(yōu)化策略

優(yōu)化核心概念是:將初次渲染不需要的CSS想辦法剝離出關(guān)鍵渲染路徑

如果僅僅是為了提前初次渲染時(shí)間而進(jìn)行優(yōu)化,將頁面必備的CSS剝離關(guān)鍵渲染路徑而造成樣式突變導(dǎo)致頁面抖動,則得不償失了

使用link/style的media屬性

對某些媒體查詢條件觸發(fā)后才使用的css,可以在link標(biāo)簽中加入 media 屬性,如下:

<link rel="stylesheet" href="index_print.css" media="print">

此樣式表仍會加載。當(dāng)瀏覽器環(huán)境不匹配媒體查詢條件時(shí),該樣式表不會阻塞渲染。我們可針對不同媒體環(huán)境拆分CSS文件,并為link標(biāo)簽添加媒體查詢,避免為了加載非關(guān)鍵CSS資源,而阻塞初次渲染

使用DOM API添加CSS

可以使用js代碼來添加css

var style = document.createElement('link');
style.rel = 'stylesheet';
style.href = 'index.css';
document.head.appendChild(style);

使用resoure hint規(guī)范的preload

將link標(biāo)簽的rel屬性設(shè)置為 preload ,瀏覽器遇到遇到標(biāo)記為preload的link時(shí),會開始加載它,但是由于rel不是 stylesheet ,因此不會阻塞渲染。

<link rel="preload" href="index_print.css" as="style" onload="this.rel='stylesheet'">

然后在適當(dāng)?shù)臅r(shí)候,在rel改為stylesheet,即可應(yīng)用此樣式。

但是這個(gè)屬性兼容性比較差,詳細(xì)可以參考 這里 。不過有一個(gè)polyfill可以用 loadCSS ,原理是通過DOM API插入樣式資源。

這個(gè)屬性的使用情景有些偏,也可能是我理解問題:

當(dāng)使用preload引入css文件時(shí),實(shí)際上證明這個(gè)頁面根本不需要這個(gè)css,它有可能是打印樣式,或者是響應(yīng)式網(wǎng)站的另一套css代碼。但是,使用preload屬性,瀏覽器反而會預(yù)先加載它,也就是說,在window.onload之前,用戶將耗費(fèi)了網(wǎng)絡(luò)資源在加載一個(gè)暫時(shí)不需要的樣式。網(wǎng)絡(luò)資源不可能是無限的,也就是說這個(gè)css會占用頁面其他資源比如圖片的網(wǎng)絡(luò)資源。

詢問瓜瓜老師本人后,瓜瓜老師說:

舉個(gè)例子。第三屏有個(gè)廣告版,它的樣式

這樣確實(shí)這個(gè)css的緊急程度就介于關(guān)鍵渲染路徑的css與頁面圖片之間了,不過貌似這個(gè)情景很受限。

JS篇優(yōu)化策略

使用defer延遲腳本執(zhí)行

當(dāng)script標(biāo)簽擁有defer屬性時(shí),該腳本會被推遲到整個(gè)HTML文檔解析完后,再開始執(zhí)行。因此將腳本放在head中,可以提早瀏覽器對腳本文件的加載,但是卻不會阻塞parse HTML。

<script src="index.js" defer></script>
<!-- 百度統(tǒng)計(jì)代碼 -->
<script src="#js" defer></script>

注意,defer的腳本不會被css阻塞,parse HTML完成后立即執(zhí)行,但是有可能會阻塞關(guān)鍵渲染路徑。為什么說有可能呢,假如腳本文件在render tree生成前加載完畢,則會開始執(zhí)行,執(zhí)行過程中會阻塞關(guān)鍵渲染路徑。請參考這個(gè) Demo

被defer的腳本,在執(zhí)行時(shí)會嚴(yán)格按照在HTML文檔中出現(xiàn)的順序執(zhí)行,但是實(shí)際上貌似不是這樣,js文件前后文件若有依賴需慎重使用。

使用async延遲腳本執(zhí)行

和defer類似,只是當(dāng)js加載完后馬上執(zhí)行,而不在乎parse HTML是否完成,因此假如腳本比css先加載完,也會阻塞關(guān)鍵渲染路徑。

<script src="index.js" defer></script>
<!-- 百度統(tǒng)計(jì)代碼 -->
<script src="#js" defer></script>

使用DOM API

據(jù)筆者所知,這是唯一一種100%不會阻塞關(guān)鍵渲染路徑的js腳本加載方式。通過DOM API引入的js腳本會等到頁面Layout和Paint后再開始執(zhí)行,不論你將載入js文件的代碼放在head中還是body后面亦是如此。

其他的優(yōu)化

使用Web Font Loader加載字體

若不想讓字體阻塞局部渲染,可使用 Web Font Loader

網(wǎng)絡(luò)優(yōu)化篇

網(wǎng)絡(luò)優(yōu)化和CSS優(yōu)化策略相同,盡可能讓關(guān)鍵資源提前加載完,所以優(yōu)化時(shí)盡量將以下指標(biāo)壓縮到最低:

  • 關(guān)鍵資源數(shù)

  • 關(guān)鍵資源體積

  • 關(guān)鍵資源網(wǎng)絡(luò)來回?cái)?shù)

當(dāng)然,如果你的項(xiàng)目使用了先進(jìn)的SPDY或HTTP/2,下面的方法可能并不適用。

優(yōu)化關(guān)鍵資源數(shù)

RFC2616規(guī)定同域名同時(shí)只能有 2 個(gè)連接(RFC7230 中無限制),而現(xiàn)代瀏覽器一般允許同域6個(gè)并發(fā)連接。因此,當(dāng)頁面中有許多需要外鏈的資源(script、link等),瀏覽器最多在每個(gè)域同時(shí)并發(fā)下載6個(gè)。

每一個(gè)請求,若使用域名,則需要額外增加一次DNS查詢時(shí)間(若緩存未過期會命中緩存),因此一個(gè)網(wǎng)站過多的使用不同域名的資源會額外增加DNS查詢開銷,這點(diǎn)在移動端非常明顯。

當(dāng)然,每個(gè)請求建立根據(jù)TCP協(xié)議規(guī)定,還需要先進(jìn)行3次捂手才可以建立鏈接。

合并請求

盡可能的合并請求,減少網(wǎng)絡(luò)請求數(shù)。這一點(diǎn)可能在其他性能優(yōu)化文章都說爛了:

  • 小圖片轉(zhuǎn)base64

  • 合并打包CSS、JS文件

現(xiàn)在的比較流行的webpack就非常擅長做這種事情

適度使用內(nèi)聯(lián)CSS和Js

使用內(nèi)聯(lián)的CSS和JS固然可以減少請求,但是使用內(nèi)聯(lián)也意味著 你的CSS和JS將不會再被瀏覽器緩存 ,因此要適度的使用內(nèi)聯(lián),內(nèi)聯(lián)不是萬能的。

從HTTP協(xié)議下手

最佳方案肯定是過渡到HTTP/2無疑,但是現(xiàn)在HTTP/2的支持并不算太好,而且各大瀏覽器僅支持TLS下實(shí)現(xiàn)的HTTP/2(說白了就是HTTPS),使得HTTP/2的使用存在許些限制。

如果沒有HTTP/2,或許可以:

  • 使用 Keep-Alive 可以規(guī)避TCP三次握手的時(shí)間

  • 使用 Transfer-Encoding:chunked 分塊輸出文件,還記得parse HTML的過程是增量的嗎?若瀏覽器可以邊下載HTML文件邊解析,豈不美哉?

  • 減少重定向,這個(gè)看上去理所當(dāng)然但是實(shí)際上卻很容易被忽略

適度使用域名散列

瀏覽器同域并行下載數(shù)量有限,所以只要多建立幾個(gè)二級域名就好了,然后合理的分配各個(gè)資源就好了。

假如由于某些不可抗拒原因,關(guān)鍵資源數(shù)是12個(gè),那么只要建立2個(gè)二級域名分別分配給其中的12個(gè)資源,瀏覽器會同時(shí)并行下載它們了。

不過,使用域名散列要適度,每一個(gè)域名都需要額外的增加一次DNS查詢時(shí)間。當(dāng)然,DNS本身也有緩存,或許適當(dāng)?shù)脑黾覦NS TTL時(shí)間也是個(gè)不錯(cuò)的主意。

壓縮關(guān)鍵資源體積

對于js、css文件,現(xiàn)在網(wǎng)上現(xiàn)成的壓縮工具一堆,而且應(yīng)用十分廣泛,相信大家都知道了,這里就不多說了。

說到壓縮,服務(wù)器開啟一定的壓縮策略(如gzip)是個(gè)不錯(cuò)的主意,效果拔群,資源大概會壓縮到原有的1/3左右。

圖片壓縮,這個(gè)需要知道什么情境下適合什么類型的圖片,GIF、JPG、PNG使用情景各不相同

關(guān)鍵資源網(wǎng)絡(luò)來回?cái)?shù)

假如一個(gè)頁面需要引入2個(gè)CSS才能工作,下面有2種方式

  • 2個(gè)均用link引入

  • 1個(gè)用link引入,在css中import另一個(gè)css

毫無疑問肯定是前者快,因?yàn)榍罢叩木W(wǎng)絡(luò)來回?cái)?shù)是1,而后者是2。

因此,盡可能將資源加載扁平化,減少關(guān)鍵資源網(wǎng)絡(luò)來回?cái)?shù)是個(gè)不錯(cuò)的主意。

當(dāng)然,優(yōu)化時(shí)要注意的點(diǎn)也有不少,比如前面提到的瀏覽器同域并發(fā)限制等,需要權(quán)衡使其不要影響到其他的導(dǎo)致初次渲染時(shí)間延后。

一些無效的優(yōu)化策略

使用 document.write 打印link標(biāo)簽引入css仍會阻塞初次渲染。

 

 

來自:https://segmentfault.com/a/1190000009218328

 

標(biāo)簽: dns dns查詢 代碼 二級域名 服務(wù)器 腳本 媒體 網(wǎng)絡(luò) 域名

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點(diǎn)!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請與原作者聯(lián)系。

上一篇:WebView 緩存原理分析和應(yīng)用

下一篇:Python高手都知道的內(nèi)置函數(shù),你不知道就low了