web
前端應用的開發與部署過程:javascript
輸入url
到頁面顯示出來的過程:css
請求過程當中一些潛在的性能優化點:html
dns
是否能夠經過緩存減小dns
查詢時間?http
請求的大小和次數?總結:深刻理解http
請求的過程是前端性能優化的核心。前端
優化核心vue
http
請求數量;google
首頁案例學習java
html
壓縮;css
壓縮;js
的壓縮和混亂;gzip
;html
壓縮HTML
代碼壓縮就是壓縮一些在文本文件中有意義,可是在HTML
中不顯示的字符,包括空格,製表符,換行符等,還有一些其餘意義的字符,如HTML
註釋也能夠被壓縮;node
一個簡單的計算:webpack
google
的流量,佔到整個互聯網的40%
,預計2016
年全球網絡流量將達到1.3ZB(1ZB = 10^9TB)
,那麼google
在2016
年的流量就是1.3ZB * 40%
,若是google
每1MB
請求減小一個字節,每一年能夠節省流量近500TB
流量。ios
如何進行html
壓縮git
nodejs
提供的html-minifier
工具;css
代碼壓縮分爲兩部分:
css
語義合併;如何進行css
壓縮
html-minifier
對html
中的css
進行壓縮;clean-css
對css
進行壓縮;js
壓縮與混亂(醜化)包括:
JS
壓縮與混亂(醜化)
html-minifier
對html
中的js
進行壓縮;uglify.js2
對js
進行壓縮;文件合併的好處:
左邊的表示使用http
長連接keep-alive
但不合並請求的狀況,須要分三次去獲取a.js
、b.js
、c.js
;右邊是使用長連接而且合併請求的狀況,只須要發送一次獲取合併文件a-b-c.js
的請求,就能將三個文件都請求回來。
不合並請求有下列缺點:
N-1
個網絡延遲;keep-alive
自己也存在問題:通過代理服務器時可能會被斷開;文件合併存在的問題
js
文件的時候,若是頁面渲染只依賴a.js
文件,因爲文件合併,須要等待合併後的a-b-c.js
文件請求回來才能繼續渲染,這樣就會致使頁面渲染速度變慢。這種狀況大多出如今現代化的前端框架,如Vue
等的使用過程當中;a-b-c.js
中只要其中一個文件(好比a.js
)發生變化,那麼整個合併文件都將失效,而不採用文件合併就不會出現這種狀況;使用建議
js
文件單獨合併:好比在單頁面應用SPA
中,當路由跳轉到具體的頁面時才請求該頁面須要的js
文件;如何進行文件合併
nodejs
實現文件合併;webpack
等前端構件化工具也能夠很好地實現;有損壓縮過程:
一張JPG
圖片的解析分別要進行:
RGB
的顏色空間轉到其餘的顏色空間 ;DCT
過程:對高頻的顏色採樣結果進行壓縮,這樣壓縮的收益會比較大;encoding
);最終獲得JPEG-Compressed Image Data
,即真正顯示出來的JPG
圖片。雖然這是一種有損壓縮,可是不少狀況下,這些損失的數據並不影響顯示;
png8/png24/png32
之間的區別
png8
:256
色 +
支持透明;png24
:2^24
色 +
不支持透明;png32
:2^32
色 +
支持透明;不一樣格式圖片經常使用的業務場景
jpg
有損壓縮,壓縮率高,支持透明;應用:大部分不須要透明圖片的業務場景;png
支持透明,瀏覽器兼容好;應用:大部分須要透明圖片的業務場景;webp
(2010
年由谷歌推出)壓縮程度更好,在ios webview
中有兼容性問題;應用:安卓所有;svg
矢量圖,代碼內嵌,相對較小,用於圖片樣式相對簡單的場景;應用:好比logo
和iconfont
;針對真實圖片狀況,捨棄一些相對可有可無的色彩信息,對圖片進行壓縮;好比在線壓縮網站:https://tinypng.com/
css
雪碧圖將網站上用到的一些圖片整合到一張單獨的圖片中,從而減小網站HTTP
請求數量。原理爲:設定整張雪碧圖可示區域,將想要顯示的圖標定位到該處(左上角);缺點:整合圖片比較大時,一次加載比較慢。
如天貓的雪碧圖:
不少狀況下,並非全部的小圖標都放在一張雪碧圖中,而是會適當進行拆分。如今使用雪碧圖的場景比較少了。
自動生成雪碧圖樣式的網站:http://www.spritecow.com/
選中雪碧圖中對應的圖標,就會生成對應的樣式。
Image inline
)將圖片的內容內嵌到html
當中,減小網站的HTTP
請求數量,經常使用於處理小圖標和背景圖片。網頁內聯圖片寫法爲:
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA..." alt="">
瀏覽器上的表現形式爲:
這裏提供一個將:image
轉 DataUrI
的網址:http://tool.c7sky.com/datauri/
缺點:
ie8
以上瀏覽器;1000kb
的圖片,base64
編碼會使圖片大小增大,致使網頁總體下載速度減慢;因此要根據場景使用,不過內聯圖片減小HTTP
請求的優勢仍是很顯著的。好比,在開發中小於4KB
或8KB
的圖片都會經過構建工具自動inline
到HTML
中,這種狀況下Image inline
帶來的圖片大小增加實際上是比增長HTTP
請求次數更優的。
SVG
與iconfont
使用iconfont
解決icon
問題
應儘可能使用該方式,好比能夠採用阿里巴巴矢量圖庫:
能夠選擇格式進行下載:
能夠看到它們的大小有着明顯的差別:
使用SVG
進行矢量圖的控制
SVG
意爲可縮放矢量圖形(Scalable Vector Graphics
)。SVG
使用 XML
格式定義圖像。下爲示例:
在線轉換網站:http://www.bejson.com/convert/image_to_svg/
webp
webp
的優點體如今它具備更優的圖像壓縮算法,能帶來更小的圖片體積,並且擁有肉眼識別無差別的圖像質量;同時具有了無損和有損的壓縮模式、Alpha
透明以及動畫的特性。在JPEG
和PNG
上的轉化效果都很是優秀、穩定和統一。安卓上不存在兼容性問題,推薦安卓下使用。
如下爲淘寶網首頁請求的圖片:
能夠看到,圖片中大量地添加了webp
格式的選擇。.jpg_.webp
表示當瀏覽器支持webp
時採用webp
格式,不然採用jpg
格式。
下面爲B
站首頁的圖片,能夠看到基本都採用了webp
格式:
同一張圖片jpg
格式和webp
格式壓縮率有着明顯的差別:
能夠經過在線網站將圖片轉換爲webp
:https://zhitu.isux.us/
像圖片這樣的靜態文件能夠存放在CDN
服務器上,讓CDN
服務器批量地將圖片轉換成Webp
格式;
版本一:
版本二:
一個渲染引擎主要包括:HTML
解析器,CSS
解析器,javascript
引擎,佈局layout
模塊,繪圖模塊:
HTML
解析器:解釋HTML
文檔的解析器,主要做用是將HTML
文本解釋成DOM
樹;CSS
解析器:它的做用是爲DOM
中的各個元素對象計算出樣式信息,爲佈局提供基礎設施;Javascript
引擎:使用Javascript
代碼能夠修改網頁的內容,也能修改css
的信息,javascript
引擎可以解釋javascript
代碼,並經過DOM
接口和CSS
樹接口來修改網頁內容和樣式信息,從而改變渲染的結果;layout
):在DOM
建立以後,Webkit
須要將其中的元素對象一樣式信息結合起來,計算他們的大小位置等佈局信息,造成一個能表達這全部信息的內部表示模型;paint
):使用圖形庫將佈局計算後的各個網頁的節點繪製成圖像結果;瀏覽器渲染頁面的整個過程:瀏覽器會從上到下解析文檔。
瀏覽器解析時碰見 HTML
標記,就會調用HTML
解析器解析爲對應的 token
(一個token
就是一個標籤文本的序列化)並構建 DOM
樹(就是一塊內存,保存着tokens
,創建它們之間的關係)。在生成DOM
的最開始階段(應該是Bytes
→ characters
後),並行發起css
、圖片、js
的請求,不管他們是否在HEAD
標籤中。
注意:發起
js
文件的下載請求(request
)並不須要DOM
處理到那個script
節點;
碰見 style/link
標記 調用解析器 處理 CSS
標記並構建 CSS
樣式樹;
碰見 script
標記 調用 javascript
解析器處理script
標記,綁定事件、修改DOM
樹/CSS
樹等;
將 DOM
樹 與 CSS
樹 合併成一棵渲染樹(Render Tree
)。
佈局(Layout
):根據渲染樹中各節點的樣式和依賴關係,計算出每一個節點在屏幕中的位置;
繪圖(Painting
):按照計算出來的結果:要顯示的節點、節點的CSS
與位置信息,經過顯卡,把內容畫到屏幕上;
通過第一次Painting
以後DOM
、CSSOM
、Render Tree
均可能會被屢次更新,好比JS
修改了DOM
或者CSS
屬性時,Layout
和Painting
就會被重複執行。除了DOM
、CSSOM
更新的緣由外,圖片下載完成後也須要調用Layout
和 Painting
來更新網頁。
補充:
HTML
中可能會引入不少的css、js
這樣的外部資源,這些外部資源在瀏覽器端是併發加載的。可是瀏覽器會對同一域名進行併發數量(度)的限制,即單個域名的併發度是有限的;- 因此,常常將大部分的資源託管到
CDN
服務器上,而且設置3~4
個CDN
域名。防止只有一個CDN
域名的狀況下,達到了瀏覽器外部資源併發請求數目的上限,致使不少資源沒法作到併發請求。因此,應設置多個CDN
域名;
css
阻塞只有經過link
引入的外部css
纔會產生阻塞:
style
標籤中的樣式:
html
解析器進行解析;DOM
解析;link
引入的外部css
樣式(推薦使用的方式):
CSS
解析器進行解析;css
已經加載完畢,因此整個渲染過程是帶樣式的,因此這種阻塞能夠避免「閃屏現象」;js
語句的執行:這個不難理解,js
文件中常常會出現DOM
操做,操做過程當中有可能涉及到css
樣式的修改。實際上,這些修改每每是依賴於以前引入的css
設定的樣式的,因此css
會阻塞js
的執行;優化核心理念:儘量快的提升外部css
加載速度:
CDN
節點進行外部資源加速;css
進行壓縮(利用打包工具,好比webpack
,gulp
等);http
請求數,將多個css
文件合併;js
阻塞阻塞DOM解析:
緣由:瀏覽器不知道後續腳本的內容,若是先去解析了下面的DOM
,而隨後的js
刪除了後面全部的DOM
,那麼瀏覽器就作了無用功,瀏覽器沒法預估腳本里面具體作了什麼操做,例如像document.write
這種操做,索性所有停住,等腳本執行完了,瀏覽器再繼續向下解析DOM
;能夠經過給script
標籤添加defer
和async
屬性,異步引入js
文件,以此來解決這一問題。
阻塞頁面渲染:
緣由:js
中也能夠給DOM
設置樣式,瀏覽器一樣等該腳本執行完畢,再繼續幹活,避免作無用功;
阻塞後續js
的執行:
緣由:js
是按順序執行的,這樣能夠維護依賴關係,例如:必須先引入jQuery
再引入bootstrap
;
不阻塞資源的加載:
這並不與上面矛盾,由於不可能因爲加載一個js
文件就把其餘資源的加載都阻塞了。針對這種常見的狀況,瀏覽器會經過預加載的方式加載後續的資源;
css
的解析和js
的執行是互斥的(互相排斥),css
解析的時候js
中止執行,js
執行的時候css
中止解析;
不管css
阻塞,仍是js
阻塞,都不會阻塞瀏覽器加載外部資源(圖片、視頻、樣式、腳本等);
由於覽器始終處於一種:「先把請求發出去」的工做模式,只要是涉及到網絡請求的內容,不管是:圖片、樣式、腳本,都會先發送請求去獲取資源,至於資源到本地以後何時用,由瀏覽器本身協調。顯然這種作法效率很高;
WebKit
和Firefox
都進行了【預解析】這項優化。在執行js
腳本時,瀏覽器的其餘線程會解析文檔的其他部分,找出並加載須要經過網絡加載的其餘資源。經過這種方式,資源能夠在並行鏈接上加載,從而提升整體速度。請注意,預解析器不會修改 DOM
樹
圖片進入可視區域以後再請求圖片資源的方式稱爲圖片懶加載。適用於圖片不少,頁面很長的業務場景,好比電商;
懶加載的做用:
減小無效資源的加載:
好比一個網站有十頁圖片,用戶只查看了第一頁的圖片,這就不必將十頁圖片全都加載出來;
併發加載的資源過多會阻塞js
的加載,影響網站正常的使用:
因爲瀏覽器對某一個host name
是有併發度上限的,若是圖片資源所在的CDN
和靜態資源所在的CDN
是同一個的話,過多圖片的併發加載就會阻塞後續js
文件的併發加載。
懶加載實現的原理:
監聽onscroll
事件,判斷可視區域位置:
圖片的加載是依賴於src
路徑的,首先能夠爲全部懶加載的靜態資源添加自定義屬性字段,用於存儲真實的url
。好比是圖片的話,能夠定義data-src
屬性存儲真實的圖片地址,src
指向loading
的圖片或佔位符。而後當資源進入視口的時候,纔將src
屬性值替換成data-src
中存放的真實url
。
<img src="" class="image-item" alt="" lazyload = "true" data-src="TB27YQvbm_I8KJjy0FoXXaFnVXa_!!400677031.jpg_180x180xzq90.jpg_.webp">
懶加載實例
能夠使用元素的getBoundingRect().top
來判斷當前位置是否在視口內,也能夠使用元素距離文檔頂部的距離offsetTop
和scrollTop
是否小於視口高度來判斷:
舉例
好比手機淘寶首頁:
當快要滾動到須要展現的圖片時才進行圖片的請求,能夠看到圖片上有一個lazyload
的屬性:
預加載與懶加載正好是相反的過程:懶加載其實是延遲加載,將咱們所需的靜態資源加載時間延後;而預加載是將圖片等靜態資源在使用以前的提早請求,這樣資源在使用到時能從緩存中直接加載,從而提高用戶體驗;
預加載的做用:
提早請求資源,提高加載速度:使用時只須要讀取瀏覽器緩存中提早請求到的資源便可;
維護頁面的依賴關係:好比WebGL
頁面,會依賴一些3D
模型,這些都是頁面渲染所必須的資源。若是資源都沒有加載完畢就進行頁面的渲染,就會形成很是很差的體驗。
因此時常使用預加載的方式維護頁面渲染的依賴關係,好比將WebGL
頁面依賴的3D
模型加載完以後才進行頁面渲染。這樣渲染的過程就不會有任何阻礙,具備較好的用戶體驗;
預加載的實例
例如九宮格抽獎業務,每一個獎品都有一個選中態和非選中態,實際上這是由兩張圖片組合而成的。因爲每一個獎品的選中過程都是一瞬間,這就對圖片的選中態和非選中態切換效率要求很高,若是選中態的圖片沒有預加載的話顯然是來不及的。
因此,實際上對於九宮格中全部圖片選中態的樣式和對應的圖片都須要進行預加載,從而讓咱們在抽獎的過程當中,可以瞬間從緩存中讀取到選中態的圖片,從而不影響抽獎效果的展現。
除此以外還有網站登陸或活動時須要用到的動畫,這是在動畫須要的每幀圖片都徹底預加載完以後纔會進行顯示的。
CSS
圖層瀏覽器在渲染一個頁面時,會將頁面分爲不少個圖層,圖層有大有小,每一個圖層上有一個或多個節點。在渲染 DOM
的時候,瀏覽器所作的工做其實是:
一、獲取DOM
後分割爲多個圖層;
二、對每一個圖層的節點計算樣式結果(Recalculate style
--樣式重計算);
三、爲每一個節點生成圖形和位置(Layout
--迴流和重佈局);
四、將每一個節點繪製填充到圖層位圖中(Paint Setup
和Paint
--重繪);
五、圖層做爲紋理上傳至GUI
;
六、複合多個圖層到頁面上生成最終屏幕圖像(Composive Layers
--圖層重組);
3D
或透視變換的css
屬性(prespective transform
);<video>
節點;3D(WebGL)
上下文或加速的2D
上下文的<canvas>
節點;CSS3
動畫的插件(如Flash
);css
過濾器的元素;
transform
:如translateZ(0)
opacity
filter
will-change
:哪個屬性即將發生變化,進而進行優化。重繪是一個元素外觀的改變所觸發的瀏覽器行爲,好比background-color
、outline
等屬性。這些屬性不影響佈局,隻影響元素的外觀,風格,會形成DOM
元素的從新渲染,這個過程稱爲重繪。
須要注意的是:重繪是以圖層爲單位,若是圖層中某個元素須要重繪,那麼整個圖層都須要重繪。好比一個圖層包含不少節點,其中有個gif
圖,gif
圖的每一幀,都會重回整個圖層的其餘節點,而後生成最終的圖層位圖。
所以,能夠經過特殊的方式來強制gif
圖單獨爲一個圖層(translateZ(0)
或者translate3d(0,0,0)
;CSS3
的動畫也是同樣(好在絕大部分狀況瀏覽器本身會爲CSS3
動畫的節點建立圖層);
因此:將頻繁重繪迴流的DOM
元素做爲一個獨立圖層,那麼這個DOM
元素的重繪和迴流只會該圖層;原則上是要儘可能避免新建圖層的,由於這會致使圖層重組(Composive Layers
)時候的計算量增大。因此,只有當某些DOM
元素頻繁重繪迴流時,才新建一個獨立圖層放置它們;
只會觸發重繪的屬性
//部分屬性 color border-style border-radius visibility text-decoration background background-image background-position background-repeat background-size outline-color outline outline-style outline-width box-shadow
當render tree
中的一部分(或所有)由於元素的規模尺寸,佈局,隱藏等改變而須要從新構建。這就稱爲迴流(reflow
);
當頁面佈局和幾何屬性改變時就須要迴流;
迴流必將引發重繪,而重繪不必定會引發迴流;
觸發頁面重佈局(迴流)的屬性
盒子模型相關屬性 | 定位及浮動屬性 | 文字結構屬性 |
---|---|---|
width | top | text-align |
height | bottom | overflow-y |
padding | left | font-weight |
margin | right | overflow |
display | position | font-family |
border-width | float | line-height |
border | clear | vertical-align |
min-height | * | white-space |
* | * | font-size |
頻繁觸發重繪和迴流,會致使UI
頻繁渲染。在渲染的過程當中因爲阻塞了js
線程的執行,最終致使js
執行變慢。
增長、刪除、修改 DOM
結點;
移動 DOM
的位置;
修改 CSS
樣式;
Resize
窗口;移動端沒有這個問題,由於移動端的縮放沒有影響佈局視口(vw/vh
);
修改網頁的默認字體;
獲取某些DOM
元素的屬性(width
,height
等);
注:
display:none
會觸發Reflow
,而visibility:hidden
只會觸發Repaint
,由於沒有發生位置變化;
案例一:淘寶輪播圖
能夠使用Chrome
瀏覽器調試工具的Performance
來觀察淘寶首頁一個輪播圖引發的重繪迴流過程:
Update Layer Tree
迴流和重佈局:
Paint
重繪:
Composite Layers
圖層重組:
案例二:播放器
經過Chrome
調試工具的Layers
選項查看圖層,及新增圖層的緣由:
視頻播放的過程當中,video
標籤的DOM
元素會一直重繪,因此把它限制在一個圖層上是很是好的,這樣只會涉及到這個圖層的重繪,而不會影響其餘圖層的元素。
圖層不能濫用,不然會在圖層重組的過程當中嚴重消耗性能!
好比能夠將淘寶首頁的全部的DOM
元素都變爲一個圖層:在html
標籤中的全局樣式(*
)中添加transform:translateZ(0)
來觸發新建圖層:
還能夠經過添加:
will-change: transform
屬性新建圖層;
再次查看此時的圖層狀況,能夠看到此時首頁的圖層很是之多,十分地卡:
若是咱們須要使得動畫或其餘節點渲染的性能提升,須要作的就是減小瀏覽器在運行時所須要作的下列工做:
Recalculate style
--樣式重計算);Layout
--迴流和重佈局);Paint Setup
和Paint
--重繪);Composite Layers
--圖層重組);一、使用translate
替代top
等屬性來改變位置;
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> #box{ /*方法1*/ position: relative; top: 0; /*方法2*/ /* transform: translateY(0); */ width: 200px; height: 200px; background-color: pink; } </style> </head> <body> <div id="box"></div> <script> setTimeout(() => { document.getElementById("box").style.top = '100px' //document.getElementById("box").style.transform = 'translateY(100px)' }, 2000); </script> </body> </html>
使用top
屬性改變正方形位置時,存在重繪和迴流Layout
:
而使用translate
屬性改變正方形位置時,並不會引發重繪和迴流:
好比有的網站會有一些左右飄動的浮窗,因爲這些浮窗是採用定時器來實現的,若是每通過100ms
就改變浮窗的位置。這種時候使用transform
來替代top/left
的話1s
內就減小了十次迴流,十分有利於網頁速度的提高。
二、使用opacity
替代visibility
:
使用visibility
不觸發重排,可是依然重繪;
直接使用opacity
既觸發重繪,又觸發重排(GPU
底層設計如此!);
opacity
配合圖層使用,既不觸發重繪也不觸發重排;
緣由:透明度的改變時,GPU
在繪畫時只是簡單的下降以前已經畫好的紋理的alpha
值來達到效果,並不須要總體的重繪。不過這個前提是這個被修改opacity
自己必須是一個單獨的圖層。
三、將屢次改變DOM
元素樣式屬性的操做合併成一次操做:
class
,而後經過修改DOM
的className
來添加樣式;四、把DOM
離線後再修改:
display
屬性爲none
的元素不在渲染樹中,對隱藏的元素操做不會引起其餘元素的重排。若是要對一個元素進行復雜的操做時,能夠先隱藏它,操做完成後再顯示。這樣只在隱藏和顯示時觸發2
次迴流;五、不要把獲取某些DOM
節點的屬性值放在一個循環裏當成循環的變量
當向瀏覽器請求某些 style
信息的時候,瀏覽器就會清空(flush
)隊列,好比:
ffsetTop
,offsetLeft
,offsetWidth
,offsetHeight
;
scrollTop/Left/Width/Height
;
clientTop/Left/Width/Height
;
width
,height
;
瀏覽器爲了獲取最精確的值,須要刷新內部隊列。由於隊列中可能存在影響到這些值的操做,即便沒有,瀏覽器也會強行刷新渲染隊列。這樣就沒法利用渲染隊列的緩存來避免迴流過於頻繁了,因此在使用到DOM
元素這些相關的屬性時,能夠將獲取到的屬性值存在一個變量中,而不是每次都去從新獲取。
六、不要使用table
佈局:
table
的從新佈局;因此儘可能使用div
佈局;七、啓用GPU
硬件加速:
原理爲:瀏覽器會檢測一些特定的css
屬性,當DOM
元素擁有這些css
屬性的時候,瀏覽器就會對該DOM
元素啓動GPU
硬件加速;好比:transform: translateZ(0)
和transform: translate3d(0, 0, 0)
這兩個屬性均可以啓動硬件加速;硬件加速一樣不能濫用,不然會致使圖層過多,致使合併圖層時消耗大量性能。
八、動畫實現速度的選擇:
九、爲動畫元素新建圖層,提升動畫元素的z-index
;
十、利用文檔碎片(documentFragment
)------vue
使用了該種方式提高性能
若是咱們要在一個ul
中添加10000
個li
,若是不使用文檔碎片,那麼咱們就須要使用append
進行10000
次的追加,這會致使頁面不停地迴流,很是地消耗資源:
var oUl = document.createElement("ul"); for(var i=0;i<10000;i++) { var oLi = document.createElement("li"); oUl.appendChild(oLi); } document.body.appendChild(oUl);
咱們能夠引入createDocumentFragment()
方法,它的做用是建立一個文檔碎片。先將要插入10000
個li
添加到文檔碎片裏,而後再一次性添加到document
中。即文檔碎片至關於一個臨時倉庫,這樣可以大量減小DOM
操做:
//先建立文檔碎片 var oFragment = document.createDocumentFragment(); //再建立ul標籤 var oUl = document.createElement("ul"); for(var i=0;i<10000;i++) { //建立li標籤 var oLi = document.createElement("li"); //先附加在文檔碎片中 oFragment.appendChild(oLi); } //將文檔碎片添加到ul標籤中 oUl.appendChild(oFragment); //將ul標籤添加到body標籤中 document.body.appendChild(oUl);
十、使用requestAnimationFrame
製做動畫:詳細內容以下。
requestAnimationFrame
)window.requestAnimationFrame()
:該方法會告訴瀏覽器在重繪以前調用指定的函數:
參數:該方法以一個回調函數做爲參數,這個回調函數會在瀏覽器重繪以前被調用;
回調函數會被自動傳入一個參數:DOMHighResTimeStamp
,標識requestAnimationFrame()
開始觸發回調函數的當前時間;
返回值: 一個非零的整數,也稱爲請求ID
,是回調列表中惟一的標識,沒有其餘意義;
window.cancelAnimationFrame(requestID)
:該方法取消一個先前經過調用window.requestAnimationFrame()
方法添加到計劃中的動畫幀請求。requestID
是先前調用window.requestAnimationFrame()
方法時返回的ID
。
用途
CSS3
製做動畫的狀況下,使用這種方法替代定時器製做動畫;示例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> #box{ height: 200px; width: 200px; background-color: pink; } </style> </head> <body> <div id="box"></div> <script> let i = 0 //獲取請求ID let id = requestAnimationFrame(move) function move(){ i++ document.getElementById('box').style.transform = `translateX(${i}px)` //遞歸調用requestAnimationFrame,更新請求ID,實現動畫效果 id = requestAnimationFrame(move) } setTimeout(() => { //2s後中止動畫 cancelAnimationFrame(id) }, 2000); </script> </body> </html>
代碼實現
function debounce(fn,delay){ var timer = null // 清除上一次延時器 return function(){ clearTimeout(timer) // 從新設置一個新的延時器 timer = setTimeout(() => { fn.call(this) }, delay); } }
使用函數防抖能夠減小事件觸發的次數和頻率,在某些狀況下能夠起到優化的做用。好比:搜索框,對於核心業務非搜索的網站,通常都是等待用戶完整輸入內容後才發送查詢請求,一次來減小服務器的壓力。像百度這樣的核心業務爲搜索的網站,服務器性能足夠強大,因此不進行函數防抖處理;
概念:不斷觸發一個函數後,執行第一次,只有大於設定的執行週期後纔會執行第二次,以此控制函數執行頻率;
實現:定時器,標識;
應用:在遊戲中,能夠設定人物攻擊動做的最快頻率,不管手速多快也沒法超越這一頻率;
代碼實現
/* 節流函數:fn:要被節流的函數,delay:規定的時間 */ function throttle(fn, delay){ // 記錄上一次函數出發的時間 var lastTime = 0 return function(){ // 記錄當前函數觸發的時間 var nowTime = new Date().getTime() // 噹噹前時間減去上一次執行時間大於這個指定間隔時間才讓他觸發這個函數 if(nowTime - lastTime > delay){ // 綁定this指向 fn.call(this) //同步時間 lastTime = nowTime } } }
Cookie
Cookie
翻譯過來是小甜餅的意思,是網景公司的前僱員 Lou Montulli
在1993
年3
月發明的;Cookie
是純文本格式,不包含任何可執行的代碼信息,伴隨着用戶請求在 Web
服務器和瀏覽器之間傳遞;Cookie
本質上屬於http
的範疇,由於http
協議自己是無狀態的,服務端是沒有辦法區分請求來自於哪一個客戶端,即使是來自於同一個客戶端的屢次請求,服務端也沒法進行區分。因此引入了Cookie
去維持客戶端的狀態(好比每一個帳號的購物車狀態都不同)。Cookie
的生成方式
客戶端生成:
在 JavaScript
中經過 document.cookie
屬性,你能夠建立、維護和刪除 Cookie
;設置 document.cookie
屬性的值並不會刪除存儲在頁面中的全部 Cookie
,它只簡單的建立或修改字符串中指定的 Cookie
。
服務端生成:
Web
服務器經過在HTTP
響應頭中添加 Set-Cookie
字段來建立一個 Cookie
,能夠在該字段中添加HttpOnly
屬性禁止JavaScript
腳本訪問Cookie
,以此來避免跨域腳本 (XSS
) 攻擊。
Cookie
的缺陷
Cookie
在HTTP
中是明文傳遞的,其中包含的數據均可以被他人訪問,出現篡改、盜用等問題;Cookie
的大小限制在4KB
左右,若要作大量存儲顯然不是理想的選擇;Cookie
是綁定域名對應的服務器的,因此對同一個域名的每次請求都會在Request Header
中帶上Cookie
。
Cookie
信息的場合下流量的浪費;這樣瀏覽器對同一域名的每一次請求都會多出4KB
流量,對於大型網站來講這是很大的損耗。所以要慎用Cookie
,不要在Cookie
中存儲重要和敏感的數據。
Cookie
性能優化的方法
將存放靜態資源的CDN
服務器域名與主站的域名獨立開來。這樣每次請求靜態文件的時候就不須要攜帶Cookie
,從而能夠節省不少流量。
舉例
好比在百度進行登陸的時候,請求頭裏面就會有Set-Cookie
字段,其中的BDUSS
就是標識用戶登陸狀態的字符串:
Set-Cookie
中的httponly
屬性表示的是禁止js
腳本訪問cookie
,這樣可以必定程度防範XSS
攻擊;
在Chrome
調試工具的Application
選項中查看Cookies
信息,能夠發現該Cookie
已經被網站「種」到Domain:.baidu.com
這個域名下了,而且該Cookie
也設置了HttpOnly
屬性:
此後瀏覽器的每次請求都會在請求頭Request Headers
中攜帶這一Cookie
信息。刷新頁面後能夠看到,請求頭中攜帶了Cookie
信息BDUSS
:
這樣服務器就知道這是已經登陸的用戶了。
可是不是全部的請求都須要攜帶Cookie
信息,好比優酷:
能夠看到請求index.css
文件時也攜帶了Cookie
,可是這是沒必要要的,這就會致使流量的浪費。
解決方法就是上面所說的:將
CDN
域名和主域名獨立出來;
百度就是這樣解決的:
能夠看到請求這個靜態資源的url
並非.baidu.com
,而是靜態資源服務器CDN
;而且該請求的請求頭中不會攜帶Cookie
信息:
設置和獲取Cookie
設置Cookie
的方式很簡單,key
和value
值經過等號鏈接:
document.cookie = "userName=zhangsan"
打開Application
選項查看當前Cookie
,能夠看到Cookie
已被改變:
獲取Cookie
:
document.cookie
備註:
- 靜態資源是不會攜帶
Cookie
的;Cookie
通常都是後臺種的,不多讓前端來直接寫;Cookie
分:持久級別、session
級別;Cookie
通常用於存放session ID
與服務器端進行通訊;
Web Storage
Web Storage
分爲SessionStorage
和LocalStorage
專門用於客戶端瀏覽器的本地存儲,同時空間比Cookie
大不少,通常支持5-10M
;
瀏覽器端經過 Window.sessionStorage
和 Window.localStorage
屬性來實現本地存儲機制;
LocalStorage
LocalStorage
是HTML5
設計出來專門用於存儲瀏覽器信息的:
5~10M
左右;js
進行讀寫等操做的API
;舉例
好比經過Chrome
調試工具的Application
選項能夠查看淘寶中LocalStorage
存儲的數據:
這些數據只要不手動清除,即便關閉頁面也都會存在。當須要使用圖片、js/css
文件等資源時就不用從新向服務器發出請求,而是能夠直接使用LocalStorage
中的緩存,這就是LocalStorage
緩存的優點;
而Cookie
就不同了,裏面存儲的數據都是要帶到服務器端的,例如用戶登陸狀態,統計信息等數據:
設置和獲取LocalStorage
LocalStorage
提供了相對簡單的API
,採用的也是key
和value
的形式。
設置時經過:
localStorage.setItem("key", "value")
查看LocalStorage
,一樣設置成功了:
獲取時經過:
localStorage.getItem("key")
其餘方法
//該方法接受一個鍵名做爲參數,並把該鍵名從存儲中刪除。 localStorage.removeItem('key'); //調用該方法會清空存儲中的全部鍵名 localStorage.clear();
SessionStorage
SessionStorage
用於存儲瀏覽器的會話信息,標籤頁關閉以後它存儲的數據就會被清空,而LocalStorage
的數據不會被清空,這是兩者的區別:
5~10M
左右;SessionStorage
中,這樣即便刷新後數據也不會丟失;還有一種場景:分頁的表單在進行前進或後退時,若是將信息保存在SessionStorage
中就不會丟失;設置和獲取SessionStorage
設置SessionStorage
的方法與設置LocalStorage
的方法相似:
//設置 sessionStorage.setItem("key", "value") //獲取 sessionStorage.getItem("key")
經過Application
選項查看SessionStorage
,可見已成功修改:
其餘方法
//該方法接受一個鍵名做爲參數,並把該鍵名從存儲中刪除。 sessionStorage.removeItem('key'); //調用該方法會清空存儲中的全部鍵名 sessionStorage.clear();
IndexedDB
IndexedDB
是瀏覽器提供的一種API
,用於存儲客戶端中大量的結構化數據。該API
使用索引來實現對數據的高性能搜索。雖然WebStorage
對於存儲較少許的數據時頗有用(採用key/value
的方式),但對於存儲更大量的結構化數據來講,仍是IndexedDB
表現更加優異。
IndexedDB
的應用
能夠在瀏覽器中打印indexedDB
對象:
PWA
PWA
(Progressive Web Apps
)是一種Web App
新模型(標準),並非具體指某一種前沿的技術或者某一個單一的知識點。從英文縮寫就能看出,這是一個漸進式的Web App
,是經過一系列新的Web
特性,配合優秀的UI
交互設計,逐步加強用戶的體驗;
PWA
的要求
Engaging
):應用能夠被增長到手機桌面,而且和普通應用同樣有全屏、推送等特性;Service Worker
Service Worker
是一個腳本,能夠使瀏覽器獨立於當前網頁,在後臺運行。爲實現一些不依賴頁面或者用戶交互的特性打開了一扇大門。在將來這些特性將包括推送信息,背景後臺同步,geofencing
(地理圍欄定位)等它將推出的第一個首要特性,就是攔截和處理網絡請求的能力,包括以編程方式來管理被緩存的響應。
即Service Worker
能夠幫助瀏覽器執行大規模的運算而不阻礙主線程的執行。
Service Worker
的應用
Service Worker
在後臺運行的同時能和頁面通訊的能力,去實現大規模後臺數據的處理;Service Worker
應用過程
示例
經過Chrome
調試工具的Application
選項能夠查看淘寶的Service Workers
信息:
當咱們刷新淘寶網頁的時候,查看Network
選項,能夠從請求文件的size
欄發現大量的文件都是從Service Worker
緩存中請求回來的:
這樣的話就能夠利用Service Worker
的緩存進行網站的性能優化。
如下列淘寶請求同一js
文件爲例,從Service Worker
中加載使用了7ms
:
使用Ctrl + F5
強制刷新後,向服務器請求同一文件花了100ms
:
這就是使用Service Worker
性能上帶來的優點。因爲是從本地緩存中讀取的資源,因此資源讀取的速度和總體的性能都會有一個明顯的提高。
緩存定義:
瀏覽器在本地磁盤上將用戶以前請求的數據存儲起來,當訪問者再次須要改數據的時候無需再次發送請求,直接從瀏覽器本地獲取數據
緩存的好處:
能夠經過Chrome
瀏覽器調試工具中的Network
選項查看瀏覽器請求資源的狀況:
注意不要勾選圖中方框內的選項,不然有些請求會被過濾;
Cache-Control
字段服務器可經過httpheader
中的Cache-Control
字段控制客戶端與服務器端之間的緩存策略,它的屬性值有:
max-age
該字段指定了緩存的最大有效時間,如下爲淘寶的一張圖片:
在max-age
屬性指定的時間未到期前,客戶端不會向服務器發起請求,而是從緩存中直接讀取該圖片。上圖中能夠看到瀏覽器直接從ServiceWorker
的緩存中讀取了該圖片資源。
Expires
字段一樣能夠指定緩存的有效期,不過這是HTTP1.0
中的字段,優先級比HTTP1.1
中的Cache-Control
字段的max-age
屬性低;
s-maxage
緩存設備整體來講有兩種:瀏覽器(客戶端)和CDN
服務器;
private
類型緩存設備,表示只有瀏覽器才能夠對資源進行緩存;CDN
服務器屬於public
類型緩存設備,這種設備能夠對源服務器上的資源進行緩存。而且,這種緩存對於任何用戶來講都是能夠訪問的;s-maxage
的優先級在Expires
和max-age
三者之中是最高的,用於指定public
類型緩存設備(好比CDN
)上資源的有效期。以下圖所示,該資源設定了該字段後,瀏覽器既不會使用瀏覽器緩存,也不會向服務器請求資源,而是向public
類型的緩存設備(如CDN
服務器)請求資源:
private
服務器端能夠經過該屬性指定某一資源只能被瀏覽器(客戶端)緩存,而不能被代理緩存服務器(CDN
)緩存。
public
服務器端能夠經過該屬性指定某一資源,既能夠被瀏覽器緩存,也能夠被代理緩存服務器緩存;
no-cache
no-cache
屬性規定了瀏覽器要先向服務器端發送請求確認緩存資源的新鮮度,才能決定是否使用緩存;以下圖所示:
no-store
該屬性指定了瀏覽器不管緩存資源是否過時直接跳過緩存,從新向服務器請求資源。no-store
屬性用的比較少。
Expires
字段這是http1.0
的規範;它的值爲一個絕對時間的GMT
(格林威治標準時間)格式時間字符串,如Mon, 10 Jun 2015 21:31:12 GMT
;
該字段指定了瀏覽器緩存資源的過時時間,在指定的時間到期前,瀏覽器能夠直接從本地緩存中讀取數據,而無需再次向服務器發起請求,屬於強緩存;相比於max-age
與s-maxage
優先級最低,在這兩個屬性存在的狀況下Expires
字段會失效;
Last-Modified/If-Modified-Since
兩者是基於客戶端和服務端協商的緩存機制,標識資源最後更新時間的字段。last-modified
字段位於response header
中,If-Modified-Since
字段位於request header
中,兩者配合着Cache-Control
字段使用。
當服務器上的資源發生改變時會同步更新last-modified
的字段值,當Expires
字段或max-age
屬性指定的時間到期後,客戶端會在請求頭中攜帶If-Modified-Since
字段,與服務器端資源的last-modified
字段值進行比較:
last-modified
字段指定的時間之後都沒有發生變化,此時服務器返回狀態碼304
,屬於協商緩存;last-modified
字段值,此時的狀態碼爲200
;舉例
下圖表示狀態碼爲304
的響應:
If-Modified-Since
字段的值爲Mon, 23 Mar 2020 18:14:15 GMT
:Last-Modified
字段的值爲Mon, 23 Mar 2020 18:14:15 GMT
:兩者相等,說明資源沒有發生變化,因此服務器返回狀態碼304
,屬於協商緩存,瀏覽器繼續使用本地緩存;
If-Modified-Since
字段的值就是服務器端上一次響應資源中的Last-Modified
字段值;
Last-Modified
的缺點
GET
;1s
內修改了N
次),If-Modified-Since
能檢查到的粒度是s
級的,這種修改沒法判斷(好比淘寶每ms
都會更新數據);因此有了
Etag/If-None-Match
Etag
字段是HTTP1.1
中的標準,是一個惟一標識服務器端資源的hash
值,該字段存在於響應頭(reponse header
)中;與請求頭(request header
)中的If-None-Match
字段及Cache-Control
字段配合使用。
只要服務器端的資源發生變化Etag
值就會改變,相比於Last-Modified
字段優先級更高且更有效;當Expires
值或者Cache-Control
字段中的max-age
值到期時,客戶端會在請求頭中攜帶If-None-Match
字段,該字段值爲服務器端上一次響應資源中的Etag
值,並與服務器端上最新資源的Etag
值進行比較:
304
,屬於協商緩存;Etag
值,此時狀態碼爲200
;舉例
下圖表示狀態碼爲304
的響應:
If-None-Match
字段值爲2da25d4039...
:Etag
字段值爲2da25d4039...
:兩者相等,說明資源沒有發生變化,因此服務器返回狀態碼304
,屬於協商緩存,瀏覽器繼續使用本地緩存;
總結:
利用
Etag
可以更加準確的控制緩存,由於Etag
是服務器自動生成或者由開發者生成的對應資源在服務器端的惟一標識符;
Last-Modified
與ETag
是能夠一塊兒使用的,因爲Etag
的優先度更高,因此服務器會優先比較Etag
和If-None-Match
。一致的狀況下,纔會繼續比對Last-Modified
和If-Modified-Since
,最後才決定是否返回狀態碼304
。
強緩存:
200 ok(from memory cache)
;協商緩存:
304
通知瀏覽器從緩存中讀取資源;緩存 | 獲取資源形式 | 狀態碼 | 發送請求到服務器 |
---|---|---|---|
強緩存 | 從緩存中獲取 | 200(from cache) |
否,直接從緩存中獲取 |
協商緩存 | 從緩存中獲取 | 304(not modified) |
是,根據服務器返回信息判斷緩存是否可用 |
最下層的200
狀態
這一層由Expires/Cache-Control
字段控制:
1.Expires
(HTTP1.0
版本有效)是絕對時間;
2.Cache-Control
(HTTP1.1
版本有效)是相對時間;
當二者都存在時,Cache-Control
會覆蓋Expires
,只要這些字段沒有失效,瀏覽器都會直接使用本地緩存,屬於強緩存;
緩存的來源大概有兩種memory cache
和disk cache
:
能夠看到,從memory cache
中讀取緩存不須要時間,從disk cache
中讀取緩存則須要必定時間。
相對時間與絕對時間與服務器的設置有關,當服務器設置
Atime
(最後訪問時間)時,兩者相等;當服務器設置Mtime
(絕對修改時間)時,Expires
從資源的建立開始計算過時時間,Max-age
從請求發起的時間開始計算過時時間;
下圖即是淘寶中採用強緩存的例子,狀態碼爲200
,圖片資源都是從瀏覽器緩存memory cache
中讀取,因此請求時間爲0ms
:
中間的304
狀態
last-modified/Etag
控制。當下一層失效時或用戶點擊refresh/F5
時,瀏覽器就會向服務器發起請求,若是服務器上的相關資源沒有更新,則返回狀態碼304
,屬於協商緩存;下圖便爲協商緩存的狀況,狀態碼爲304
。也能夠這樣理解:只要狀態碼是304
都屬於協商緩存:
最上層的200
狀態
Ctrl + F5
強制刷新時,瀏覽器會直接向服務器請求最新的資源;以下圖所示:
用戶操做 | Expires/Cache-Control |
Last-Modified/Etag |
---|---|---|
地址欄回車 | 有效 | 有效 |
頁面連接跳轉 | 有效 | 有效 |
新開窗口 | 有效 | 有效 |
前進後退 | 有效 | 有效 |
F5 刷新 |
無效 | 有效 |
Ctrl + F5 強制刷新 |
無效 | 無效 |
如圖所示,該流程圖表示服務器端在處理資源時採用緩存策略的過程:
Cache-Control
字段中添加no-store
屬性;Cache-Control
字段中添加no-cache
屬性,這樣無論緩存資源是否過時,都要求客戶端或緩存代理服務器首先向服務器確認資源的新鮮度,屬於協商緩存;Web
代理緩存資源(好比CDN
服務器緩存),若是容許則在Cache-Control
字段中添加public
屬性,並指定代理緩存服務器上資源的有效期s-maxage
;不容許則添加private
屬性,表示只能由客戶端瀏覽器緩存資源,並設定緩存的有效期max-age
;CDN
服務器網站一般將其全部的服務器都放在同一個地方,當用戶羣增長時,公司就必須在多個地理位置不一樣的服務器上部署內容。爲了縮短http
請求的時間,咱們應該把大量的靜態資源放置的離用戶近一點。
內容發佈網絡CDN
(Content Delivery Networks
)就是其中一種方式。CDN
是一組分佈在多個不一樣地理位置或網段的web
服務器,用於更加有效的向用戶發佈內容。
CDN
系統可以實時地根據網絡流量和各節點的鏈接、負載情況以及到用戶的距離和響應時間等綜合信息最簡單的CDN
網絡由一個DNS
服務器和幾臺緩存服務器組成:
URL
時,通過本地DNS
系統解析,DNS
系統最終會將域名的解析權交給CNAME
指向的CDN
專用的DNS
服務器;關於
DNS
解析,不必定由DNS
服務器響應,通常從緩存中讀取。好比電腦緩存、瀏覽器緩存、路由器緩存、運行商緩存等。若是緩存中沒有找到,才一級一級地查詢:本地DNS
-> 權限DNS
-> 頂級DNS
-> 根DNS
。全球只有13
臺根DNS
服務器。
二、CDN
的DNS
服務器將CDN
的全局負載均衡設備的IP
地址返回給用戶;
三、用戶向CDN
的全局負載均衡設備發起內容URL
訪問請求;
四、CDN
全局負載均衡設備根據用戶的IP
地址,以及用戶請求的內容URL
,選擇一臺用戶所屬區域的區域負載均衡設備,告訴用戶向這臺設備發起請求;
五、區域負載均衡設備會爲用戶選擇一臺合適的緩存服務器提供服務,選擇的依據包括:
根據用戶IP
地址,判斷哪一臺服務器距用戶最近;
根據用戶所請求的URL
中攜帶的內容名稱,判斷哪一臺服務器上有用戶所需內容;
查詢各個服務器當前的負載狀況,判斷哪一臺服務器尚有服務能力;
基於以上這些條件的綜合分析以後,CDN
區域負載均衡設備會向CDN
全局負載均衡設備返回一臺CDN
緩存服務器的IP
地址。
六、CDN
全局負載均衡設備把服務器的IP
地址返回給用戶;
七、用戶向CDN
緩存服務器發起請求,緩存服務器響應用戶請求,將用戶所需內容傳送到用戶終端;若是這臺CDN
緩存服務器上並無用戶想要的內容,可是區域均衡設備依然將它分配給了用戶,那麼這臺CDN
服務器就要向它的上一級緩存服務器請求內容,直至追溯到網站的源服務器將內容拉到本地;
網站站點/應用加速:
站點或者應用中大量靜態資源的加速分發,建議將站點內容進行動靜分離,動態文件能夠結合雲服務器ECS
,靜態資源如各種型圖片、html
、css
、js
文件等,使用CDN
服務器存儲,能夠有效加速內容加載速度,輕鬆搞定網站圖片、短視頻等內容分發。
移動應用加速:
移動APP
更新文件(apk
文件)分發,移動APP
內圖片、頁面、短視頻、UGC
等內容的優化加速分發。提供httpDNS
服務,避免DNS
劫持並得到實時精確的DNS
解析結果,有效縮短用戶訪問時間,提高用戶體驗。
視音頻點播/大文件下載分發加速;
視頻直播加速;
簡單點說CDN
服務器至關於順豐快遞分佈於全國各地的倉庫,主倉庫將快遞運送到這些分倉庫,用戶能夠就近取貨,由此加快了速度。
除此以外CDN
服務器還有許多高級功能,好比防止DDOS
攻擊等,這裏就不展開了;
SSR(Server Side Rendering)
依賴現代框架如Vue
和React
構建的網站,每每會存在必定的問題,好比Vue
框架。
Vue
渲染面臨的問題
首屏渲染時,要先下載和解析app.js
(打包事後的Vue.js
)以後,才能開始渲染頁面。
優化方案
Prerender
的方式;一般採用服務端渲染(SSR
)的方式進行優化。所謂SSR
就是利用服務器端優秀的計算能力,將一部分的頁面渲染任務交由服務器端進行處理。如下爲服務端渲染SSR
的流程圖:
服務端渲染能夠很好地優化首屏渲染的問題;能夠根據業務需求,適當地分配客戶端和服務器端的渲染部分,綜合利用客戶端和服務器端的計算能力,從而達到性能優化的目的。
參考資料: