給網(wǎng)頁設(shè)計(jì)師和前端開發(fā)者看的前端性能優(yōu)化
如果不是不可能,你也很難拒絕承認(rèn)性能目前已是任何正規(guī)網(wǎng)站項(xiàng)目的最關(guān)鍵方面之一,無論它是一個小型的網(wǎng)站組合,一個移動優(yōu)先的web應(yīng)用,一直到一個大規(guī)模的商業(yè)項(xiàng)目。研究,論文和個人體驗(yàn)都告訴我們快速是最好的。
性能不僅僅是非常重要,它也相當(dāng)?shù)挠腥?,而且這也是我越來越投入的事,不僅在工作方面(我一直在煩我們的首席性能工程師),也在項(xiàng)目與CSS魔法網(wǎng)站方面(我一直在煩Andy Davies)。
在 這篇長文章中,我將分享收獲,關(guān)于快速,簡單且非常有趣的性能知識的點(diǎn)點(diǎn)滴滴,以便使你的行為可以像一個初級的網(wǎng)頁設(shè)計(jì)師和前端開發(fā)者;希望對任何想開始 學(xué)習(xí)性能的人,這篇文章可以成為一個正規(guī)的介紹,并使它們的前端變得超快。這些技巧是你能非常容易實(shí)現(xiàn)的。它只需要一點(diǎn)小技巧,以及一些瀏覽器怎樣工作的 基礎(chǔ)知識,你就能開始玩轉(zhuǎn)系統(tǒng)了!
這篇長帖子不會講到模糊圖像的加載和數(shù)據(jù)處理,取而代之的是有關(guān)理論與第一手的性能方面的技術(shù)資料,這些技術(shù)是我通過閱讀,觀察,搜集和整理獲得的(我花費(fèi)了許多時間沉浸于CSS魔法的瀑布圖)。我也會鏈接到其它相似話題的文章,以便幫助強(qiáng)化一些關(guān)鍵要點(diǎn)。享受吧!
注意 本文需要預(yù)先知曉一些基礎(chǔ)的性能知識,如果有任何你不熟悉的就Google搜索一下好了!
基礎(chǔ)知識
關(guān) 于性能,有一些知識在所有的設(shè)計(jì)師和前端開發(fā)者中廣為傳播。例如,盡可能少的請求,優(yōu)化圖片,把樣式表(stylesheets)放 在, 把JS放在之前, 最小化(minifying) JS 和 CSS 等等。這些基礎(chǔ)知識已經(jīng) 被用來加快用戶響應(yīng)了,但還有更多更多需要學(xué)習(xí)。
雖然在我們每天的工作生活中,瀏覽器給我們制造麻煩,使我們頭疼,但請記住,他們也是很聰 明的; 它們?yōu)槲覀冏隽撕芏嘈阅軆?yōu)化工作, 所以大量的性能調(diào)優(yōu)知識不但要知道瀏覽器在哪里給我們做了優(yōu)化,還要知道怎么更好的挖掘它們。大量性能調(diào)優(yōu)訣 竅只是理解,利用和操縱瀏覽器已經(jīng)替我們做好的優(yōu)化工作。
頂部的Styles, 底部的scripts
這真的是一條基本規(guī)則,每個人都能非常容易的在大多數(shù)時間遵守,但為什么它重要?簡短的說:
CSS 塊渲染, 因此你需要立即處理它(即在文檔的頂部,在你的之中)。
JS 塊下載, 因此你需要最后處理它們,以確保它們沒有耽誤頁面中任何其它東西。
CSS 塊渲染是因?yàn)闉g覽器總是試圖漸進(jìn)式的渲染頁面;它們想在元素到達(dá)的時候順序的渲染它。如果style在距離很遠(yuǎn)的頁面下部,瀏覽器在獲得它之前沒有辦法渲 染那個CSS。因?yàn)檫@個原因,如果瀏覽器在渲染文檔過程中,改變了之前渲染的東西,它們可以避免style的重繪。瀏覽器在它獲得所有需要的style信 息之前不會渲染頁面,如果你將style放在文檔底部,你就是在使瀏覽器等待,阻塞了渲染。
所以,只要你將CSS放在頁面的頂部,那么瀏覽器就可以立刻開始渲染。
JavaScript塊下載是由于好幾個原因(這又是瀏覽器聰明之處),但首先我們需要知道瀏覽器里的資源下載是如何實(shí)際發(fā)生的;簡單的說,瀏覽器會從一個單一的域名并行的盡可能多的下載資源。它從越多的域名下載,就能在一瞬間并行的獲得更多的資源。
JavaScript中斷了這個過程,阻塞了從任何一個域名的并行的下載,因?yàn)椋?/p>
被調(diào)用的腳本可能改變頁面,即瀏覽器在繼續(xù)別的事情以前,將不得不處理它。因此為了處理那個不測事件,瀏覽器停止了任何其它東西的下載,以便集中精力關(guān)注于它。
腳本正常工作經(jīng)常需要依照一定的順序加載,例如,要在加載一個插件之前加載jQuery。瀏覽器阻止了JavaScript的并行下載,因此它不會同時下載jQuery和你的插件;很顯然如果你同時并行下載二者,你的插件會在jQuery之前到達(dá)。
所 以,由于瀏覽器在獲取JavaScript的時候停止了所有其他下載,將你的JavaScript腳本放在文檔中盡可能晚加載的地方是一個好主意。我相信 你們都看到過頁面中的空白片段,在那里第三方的JS腳本被花時間加載,并且它還阻止了頁面其他資源的獲取和渲染;這就是JavaScript的阻塞在作用 了。
但是顯然,現(xiàn)代瀏覽器還是變得聰明了。我將給你一個Andy Davies寄給我的電子郵件的摘錄,因?yàn)樗忉尩谋任仪宄?/p>
現(xiàn)代瀏覽器將并行下載JS,只有在腳本被執(zhí)行的時候阻塞渲染(顯然腳本必須也被下載了)。 腳本下載常常被瀏覽器的預(yù)加載器所完成。 當(dāng)瀏覽器頁面渲染被阻塞,即等待CSS,或JS被執(zhí)行,預(yù)分析器將掃描頁面剩余部分,尋找它能下載的資源。 有些瀏覽器如 Chrome, 將分先后下載資源,例如,如果腳本與圖片同時在等待下載,它將先下載腳本。 |
漂亮的內(nèi)容!
所以,要使頁面被盡可能快的渲染,將styles放在頂部。為了阻止JS的阻塞影響到渲染,將scripts放在底部。
更少的請求
另 一個明顯而基本的性能優(yōu)化方法是少下載。頁面需要的每一個資源就是一次額外的HTTP請求;瀏覽器不得不停下來去獲取每一個用于渲染頁面所需的資源。每一 次HTTP請求都可能引發(fā)DNS查詢,重定向,404,等等。每一次HTTP請求,無論為了樣式表,圖片,web字體,JS文件還是其它你能想到的,都可 能是一次非常昂貴的操作。盡量減少這些請求是你可以做的最快的優(yōu)化方法中的一種.
再談到瀏覽器和并行;大多數(shù)瀏覽器一次只從每個引用的域下載一些資源,而JS會阻塞這些下載。所以,你做的每一個HTTP請求都應(yīng)該仔細(xì)考慮,而不是隨便隨便做的。
盡可能并行
為了讓瀏覽器能并行的下載更多資源,你可以由不同的域名提供服務(wù)。如果說,瀏覽器只能一次從一個域名獲取兩個資源,那么由兩個域名提供服務(wù)意味著它可以一次性獲取四個資源;三個域名意味著六個并行下載。
許多網(wǎng)站有靜態(tài)/資源 域名;你可以發(fā)現(xiàn), Twitter, 用 si0.twimg.com 來做靜態(tài)資源:
-
<linkrel="stylesheet"href="https://si0.twimg.com/a/1358386289/t1/css/t1_core.bundle.css"type="text/css"media="screen">
Facebook 用fbstatic-a.akamaihd.net:
-
<linkrel="stylesheet"href="https://fbstatic-a.akamaihd.net/rsrc.php/v2/yi/r/76f893pcD3j.css">
通 過這些靜態(tài)的資源域名, Twitter與Facebook能提供更多的并行資源服務(wù);來自twitter.com和si0.twimg.com的資源可 以協(xié)作方式下載。這真的是使你的頁面上獲得更多并發(fā)下載的簡單方法,如果再加上實(shí)際的CDN技術(shù)就會更好,CDN技術(shù)通過從一個更加合適的物理位置提供資 源服務(wù)的方法來減少延遲。
這全部都很好,但后面我們將討論在特定環(huán)境下,怎樣從子域名提供服務(wù)卻會實(shí)際上對性能有害。
因此,現(xiàn)在有了我們關(guān)于性能的基礎(chǔ)知識:
·將樣式表放在文檔的頂部
·將JavaScript放在底部(可能的地方)
·盡可能減少HTTP請求
·從多個域名提供資源服務(wù)能增加瀏覽器并行下載的資源數(shù)量。
HTTP 請求與 DNS 查詢
每 當(dāng)你從任何域名請求一個資源,會發(fā)出一個帶有相關(guān)頭部,被訪問資源的 HTTP請求,并且會返回一個響應(yīng)。這是對該過程的一個極端簡化,但它基本就是事實(shí) 上你需要知道的。這是一個HTTP請求,而且所有涉及的資源都從屬于這個往返的旅行。當(dāng)提到前端性能,這些請求正是主要的瓶頸所在,因?yàn)槿缥覀冋劦降?,瀏 覽器受限于有多少請求可以并行發(fā)生。這也是為什么我們經(jīng)常要使用子域名;以便允許這些請求在數(shù)個域名上發(fā)生,允許同時發(fā)生多得多數(shù)量的請求。
然 而關(guān)于這還有個問題,DNS查詢。每次(從一個空緩存)一個新的域名被引用,HTTP請求會受制于一個耗時的DNS查詢(某個介于20到120毫秒之間的 值),在DNS查詢中,發(fā)出的請求會查詢資源實(shí)際存在的地點(diǎn);互聯(lián)網(wǎng)通過IP地址被綁定在一起,這些地址由DNS管理的主機(jī)名引用。
如果每個引用的新域名具有DNS查詢的前端代價,你必須確保這個代價確實(shí)是值得的。如果是一個小網(wǎng)站(例如像CSS魔法),那么由子域名提供資源可能并不值得;相比執(zhí)行多個域名的DNS查詢并將其并行化來說,從一個域名非并行的獲取若干資源,瀏覽器可能更快。
如 果你或許有一打資源,你可能會考慮從一個子域名提供它們的資源服務(wù);為了更好的并行化那許多資源,額外的DNS查詢可能是值得的。如果說你有40個資源, 可能將那些資源切分到兩個子域名是值得的;為了由總數(shù)為三個的域名提供你的網(wǎng)站服務(wù),兩個額外的DNS查詢會是值得的。
DNS查詢代價很高,因此你需要決定什么才是對你的網(wǎng)站更合適的;承擔(dān)查詢的消耗或者只是由一個域名提供所有服務(wù)。
很重要的需要記得的是,比方說一旦HTML被請求于foo.com,對那個主機(jī)的DNS查詢就立即發(fā)生了,所以后續(xù)的任何對foo.com的請求不再受制于DNS查詢。
DNS 預(yù)取
如 果你像我一樣想在網(wǎng)站上有一個Twitter小程序,還有網(wǎng)站分析,再也許一些網(wǎng)頁字體,那么你必須要鏈接到一些其它域名,這意味著你將不得不引發(fā)DNS 查詢。我的建議通常是,不要還沒有先適當(dāng)?shù)目紤]性能影響就使用某個或任何一個小程序,但對于你認(rèn)為確實(shí)需要的,下面的將很有用……
因?yàn)檫@些東西都存在于其它域名,比方說這就意味著你的網(wǎng)站字體CSS將會同你自己的CSS并行下載,從某種意義上說是一種好處,但是腳本將仍會阻塞(除非它們是異步的)
事實(shí)上,這里的問題是DNS查詢牽涉到了第三方域名。幸運(yùn)的是,有一個相當(dāng)快又簡單的辦法來加速這個過程:DNS預(yù)取.
DNS預(yù)取所做的恰恰就是憑證領(lǐng)餐(on the tin),它不能被簡單實(shí)現(xiàn)。比方說,如果你需要請求來自widget.foo.com的資源,那么你可以通過簡單的在頁面的里先增加下面這個來預(yù)取那個主機(jī)的DNS:
-
<head>
-
...
-
<linkrel="dns-prefetch"href="//widget.foo.com">
-
...
-
head>
那行簡單的內(nèi)容將會告訴支持的瀏覽器去開始預(yù)取那個域名的DNS,這要稍稍早于它實(shí)際需要的時刻。
本文地址:http://irelandcustomcontracting.com/tutorial/wd1496.html