前端性能優(yōu)化
離線存儲技術(shù):
https://segmentfault.com/a/1190000000732617
mainfest
怎么用糠馆?
只要在你的頁面頭部像下面一樣加入一個manifest的屬性就可以了杖剪。
<!DOCTYPE HTML>
<html manifest = "cache.manifest">
...
</html>
然后cache.manifest文件的書寫方式袋狞,就像下面這樣:
CACHE MANIFEST
#v0.11
CACHE:
js/app.js
css/style.css
NETWORK:
resourse/logo.png
FALLBACK:
/ /offline.html
離線存儲的manifest一般由三個部分組成:
1.CACHE:表示需要離線存儲的資源列表葫笼,由于包含manifest文件的頁面將被自動離線存儲袜茧,所以不需要把頁面自身也列出來。
2.NETWORK:表示在它下面列出來的資源只有在在線的情況下才能訪問撵幽,他們不會被離線存儲斯稳,所以在離線情況下無法使用這些資源。不過庄萎,如果在CACHE和NETWORK中有一個相同的資源踪少,那么這個資源還是會被離線存儲,也就是說CACHE的優(yōu)先級更高糠涛。
3.FALLBACK:表示如果訪問第一個資源失敗援奢,那么就使用第二個資源來替換他,比如上面這個文件表示的就是如果訪問根目錄下任何一個資源失敗了忍捡,那么就去訪問offline.html萝究。
一、頁面加載及渲染過程優(yōu)化
優(yōu)化 DOM
- 刪除不必要的代碼和注釋包括空格锉罐,盡量做到最小化文件帆竹。
- 可以利用 GZIP 壓縮文件。
- 結(jié)合 HTTP 緩存文件脓规。
優(yōu)化 CSSOM
- 減少關(guān)鍵 CSS 元素數(shù)量(CSSOM 縮小栽连、壓縮)
- 當我們聲明樣式表時,請密切關(guān)注媒體查詢的類型侨舆,它們極大地影響了 CRP 的性能 秒紧。
優(yōu)化 JavaScript
- 異步加載腳本延遲加載腳本
defer 跟 async 非常相似,不會阻塞頁面加載挨下,但會等到 HTML 完成解析后再執(zhí)行熔恢。
腳本添加 async 屬性,可以通知瀏覽器不要阻塞其余頁面的加載臭笆,下載腳本處于較低的優(yōu)先級叙淌。一旦下載完成秤掌,就可以執(zhí)行。
瀏覽器重繪(Repaint)和回流(Reflow)
回流必將引起重繪鹰霍,重繪不一定會引起回流闻鉴。
重繪(Repaint)
當頁面中元素樣式的改變并不影響它在文檔流中的位置時(例如:color、background-color茂洒、visibility 等)孟岛,瀏覽器會將新樣式賦予給元素并重新繪制它,這個過程稱為重繪督勺。
回流(Reflow)
當 Render Tree 中部分或全部元素的尺寸渠羞、結(jié)構(gòu)、或某些屬性發(fā)生改變時智哀,瀏覽器重新渲染部分或全部文檔的過程稱為回流次询。
會導致回流的操作:
- 頁面首次渲染
- 瀏覽器窗口大小發(fā)生改變
- 元素尺寸或位置發(fā)生改變元素內(nèi)容變化(文字數(shù)量或圖片大小等等)
- 元素字體大小變化
- 添加或者刪除可見的 DOM 元素
- 激活 CSS 偽類(例如:hover)
- 查詢某些屬性或調(diào)用某些方法
- 一些常用且會導致回流的屬性和方法
clientWidth、clientHeight盏触、clientTop、clientLeftoffsetWidth块饺、offsetHeight赞辩、offsetTop、offsetLeftscrollWidth授艰、scrollHeight辨嗽、scrollTop、scrollLeftscrollIntoView()淮腾、scrollIntoViewIfNeeded()糟需、getComputedStyle()、getBoundingClientRect()谷朝、scrollTo()
如何避免
CSS
- 避免使用 table 布局洲押。
- 盡可能在 DOM 樹的最末端改變 class。
- 避免設(shè)置多層內(nèi)聯(lián)樣式圆凰。
- 將動畫效果應(yīng)用到 position 屬性為 absolute 或 fixed 的元素上杈帐。
- 避免使用 CSS 表達式(例如:calc())。
Javascript
避免頻繁操作樣式专钉,最好一次性重寫 style 屬性挑童,或者將樣式列表定義為 class 并一次性更改 class 屬性。
避免頻繁操作 DOM跃须,創(chuàng)建一個 documentFragment站叼,在它上面應(yīng)用所有 DOM 操作,最后再把它添加到文檔中菇民。
也可以先為元素設(shè)置 display: none尽楔,操作結(jié)束后再把它顯示出來投储。因為在 display 屬性為 none 的元素上進行的 DOM 操作不會引發(fā)回流和重繪。避免頻繁讀取會引發(fā)回流/重繪的屬性翔试,如果確實需要多次使用轻要,就用一個變量緩存起來。
對具有復雜動畫的元素使用絕對定位垦缅,使它脫離文檔流冲泥,否則會引起父元素及后續(xù)元素頻繁回流。
圖片懶加載
圖片懶加載在一些圖片密集型的網(wǎng)站中運用比較多壁涎,通過圖片懶加載可以讓一些不可視的圖片不去加載凡恍,避免一次性加載過多的圖片導致請求阻塞(瀏覽器一般對同一域名下的并發(fā)請求的連接數(shù)有限制),這樣就可以提高網(wǎng)站的加載速度怔球,提高用戶體驗嚼酝。
原理
將頁面中的img標簽src指向一張小圖片或者src為空,然后定義data-src(這個屬性可以自定義命名竟坛,我才用data-src)屬性指向真實的圖片闽巩。src指向一張默認的圖片,否則當src為空時也會向服務(wù)器發(fā)送一次請求担汤∠芽纾可以指向loading的地址。注意崭歧,圖片要指定寬高隅很。
當載入頁面時,先把可視區(qū)域內(nèi)的img標簽的data-src屬性值負給src率碾,然后監(jiān)聽滾動事件叔营,把用戶即將看到的圖片加載。這樣便實現(xiàn)了懶加載所宰。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<style>
img {
display: block;
margin-bottom: 50px;
width: 400px;
height: 400px;
}
</style>
</head>
<body>
<img src="Go.png" data-src="./lifecycle.jpeg" alt="">
<img src="Go.png" data-src="./lifecycle.jpeg" alt="">
<img src="Go.png" data-src="./lifecycle.jpeg" alt="">
<img src="Go.png" data-src="./lifecycle.jpeg" alt="">
<img src="Go.png" data-src="./lifecycle.jpeg" alt="">
<img src="Go.png" data-src="./lifecycle.jpeg" alt="">
<img src="Go.png" data-src="./lifecycle.jpeg" alt="">
<img src="Go.png" data-src="./lifecycle.jpeg" alt="">
<img src="Go.png" data-src="./lifecycle.jpeg" alt="">
<img src="Go.png" data-src="./lifecycle.jpeg" alt="">
<img src="Go.png" data-src="./lifecycle.jpeg" alt="">
<script>
let num = document.getElementsByTagName('img').length;
let img = document.getElementsByTagName("img");
let n = 0; //存儲圖片加載到的位置绒尊,避免每次都從第一張圖片開始遍歷
lazyload(); //頁面載入完畢加載可是區(qū)域內(nèi)的圖片
window.onscroll = lazyload;
function lazyload() { //監(jiān)聽頁面滾動事件
let seeHeight = document.documentElement.clientHeight; //可見區(qū)域高度
let scrollTop = document.documentElement.scrollTop || document.body.scrollTop; //滾動條距離頂部高度
for (let i = n; i < num; i++) {
if (img[i].offsetTop < seeHeight + scrollTop) {
if (img[i].getAttribute("src") == "Go.png") {
img[i].src = img[i].getAttribute("data-src");
}
n = i + 1;
}
}
}
</script>
</body>
</html>
事件委托
事件委托其實就是利用JS事件冒泡機制把原本需要綁定在子元素的響應(yīng)事件(click、keydown……)委托給父元素仔粥,讓父元素擔當事件監(jiān)聽的職務(wù)垒酬。事件代理的原理是DOM元素的事件冒泡。
優(yōu)點:
- 大量減少內(nèi)存占用件炉,減少事件注冊勘究。
- 新增元素實現(xiàn)動態(tài)綁定事件
例如有一個列表需要綁定點擊事件,每一個列表項的點擊都需要返回不同的結(jié)果斟冕。
傳統(tǒng)方法會利用for循環(huán)遍歷列表為每一個列表元素綁定點擊事件口糕,當列表中元素數(shù)量非常龐大時,需要綁定大量的點擊事件磕蛇,這種方式就會產(chǎn)生性能問題景描。這種情況下利用事件委托就能很好的解決這個問題十办。
改用事件委托:
<ul id="color-list">
<li>red</li>
<li>yellow</li>
<li>blue</li>
<li>green</li>
<li>black</li>
<li>white</li>
</ul>
<script>
(function () {
var color_list = document.getElementByid('color-list');
color_list.addEventListener('click', showColor, true);
function showColor(e) {
var x = e.target;
if (x.nodeName.toLowerCase() === 'li') {
alert(x.innerHTML);
}
}
})();
</script>
二、渲染完成后的頁面交互優(yōu)化:
防抖(debounce)/節(jié)流(throttle)
防抖(debounce)
輸入搜索時超棺,可以用防抖debounce等優(yōu)化方式向族,減少http請求;
這里以滾動條事件舉例:防抖函數(shù) onscroll 結(jié)束時觸發(fā)一次棠绘,延遲執(zhí)行
function debounce(func件相, wait) {
let timeout;
return function() {
let context = this; // 指向全局
let args = arguments;
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(() => {
func.apply(context, args); // context.func(args)
}氧苍, wait);
};
}
// 使用
window.onscroll = debounce(function() {
console.log('debounce');
}夜矗, 1000);
節(jié)流(throttle)
節(jié)流函數(shù):只允許一個函數(shù)在N秒內(nèi)執(zhí)行一次。滾動條調(diào)用接口時让虐,可以用節(jié)流throttle等優(yōu)化方式紊撕,減少http請求;
下面還是一個簡單的滾動條事件節(jié)流函數(shù):節(jié)流函數(shù) onscroll 時赡突,每隔一段時間觸發(fā)一次对扶,像水滴一樣
function throttle(fn, delay) {
let prevTime = Date.now();
return function() {
let curTime = Date.now();
if (curTime - prevTime > delay) {
fn.apply(this惭缰, arguments);
prevTime = curTime;
}
};
}
// 使用
var throtteScroll = throttle(function() {
console.log('throtte');
}浪南, 1000);
window.onscroll = throtteScroll;
詳見以下鏈接:
https://zhuanlan.zhihu.com/p/113864878?from_voters_page=true
http://www.reibang.com/p/f326f33ef5cd
https://blog.csdn.net/qq_38160012/article/details/80556158