前端性能優化
沒有标準答案,越全面越好,如果做不到,就盡量從前端角度考慮
原則
- 多使用記憶體,緩存(以空間換時間,這種思想也适用于背景)通路頻繁,變化不大
- 減少 CPU 計算量,減少網絡加載耗時
入手
1、 提升加載速度
- 減少資源體積:壓縮代碼(如QQ的圖檔壓縮等)
- 減少通路次數:合并代碼,SSR服務端渲染、緩存等
- 使用更快的網絡:CDN
- CSS 放在 head,JS 放在 body 最下面
- 盡早開始執行 JS,用 DOMContentLoaded 觸發
- 懶加載(圖檔懶加載,上滑懶加載)
2、 提升渲染速度
- 對 DOM 查詢進行緩存
- 拼單 DOM 操作,合并到一起插入 DOM 結構
- 節流 throttle 防抖 debounce
防抖
示例:輸入框的 keyup 事件
防抖處理
下面代碼使用定時器對 keyup 事件進行了防抖處理,核心原則就是
- 當使用者 1000ms 之内沒有再次輸入,就對文本框的内容進行處理(這裡隻是簡單的輸出)
- 如果使用者在 1000ms 之内繼續輸入,則清除上次的定時器,自然就不會對文本框内容進行處理了
- 也就是說,最終隻會對最後一次輸入進行處理
- 試想,如果是實時驗證使用者名是否可用的需求,做了防抖處理後,能夠大大減輕伺服器的壓力,減少請求次數
代碼示範:
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>防抖</title>
</head>
<body>
<input type="text" name="" id="userName">
<script>
const txt_userName = document.querySelector('#userName')
txt_userName.addEventListener('keyup', debounce(() => {
console.log(this);
console.log(txt_userName.value);
}))
// 封裝防抖函數
function debounce(callback, delay = 1000) {
let timer = null
return function () {
if (timer) {
// 可取消由 setTimeout() 方法設定的 timeout
clearTimeout(timer)
}
timer = setTimeout(() => {
// 事件處理代碼
callback && callback()
timer = null
}, delay)
}
}
</script>
</body>
</html>
節流
示例:拖拽元素
- 拖拽元素時,要随時拿到被拖拽元素的位置
- 直接用 drag 事件,會頻繁觸發,很容易導緻卡頓
- 節流:無論拖拽速度多快,都會每隔 100ms 觸發一次
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>節流</title>
<style>
.box {
width: 200px;
height: 150px;
background-color: rgb(175, 95, 250);
}
</style>
</head>
<body>
<div class="box" draggable="true"></div>
<script>
const box = document.querySelector('.box')
box.addEventListener('drag', throttling((e) => {
console.log(e);
}))
function throttling(callback, delay=1000) {
let timer = null
return function() {
if(timer) return
timer = setTimeout(() => {
callback && callback.apply(this,arguments)
timer = null
},delay)
}
}
</script>
</body>
</html>
圖檔懶加載
css樣式
<style>
body {
width: 100%;
height: 100%;
}
img {
width: 200px;
height: 280px;
}
</style>
html代碼
<body>
<div>
<div>
<h2>白敬亭也太帥了吧</h2>
<p>今天又是被小白帥炸的一天哦!!!啦啦啦啦啦~~~~~</p>
<img src="" alt="" src="https://www.77wenyu.com/uploads/img1/20200712/8cf365eed29433fdf0a28882491da083.jpg">
</div>
<div>
<h2>白敬亭也太帥了吧</h2>
<p>今天又是被小白帥炸的一天哦!!!啦啦啦啦啦~~~~~</p>
<img src=""
src="https://star-img.idol001.com/atlas/7177/images/2018/2/6/C58r63d4j41517896392282.jpg/default-w720"
alt="">
</div>
<div>
<h2>白敬亭也太帥了吧</h2>
<p>今天又是被小白帥炸的一天哦!!!啦啦啦啦啦~~~~~</p>
<img src="" alt=""
src="https://uploadfile.bizhizu.cn/up/92/d4/87/92d487a2c3f10ad62061bfccbbeacff7.jpg.source.jpg">
</div>
<div>
<h2>白敬亭也太帥了吧</h2>
<p>今天又是被小白帥炸的一天哦!!!啦啦啦啦啦~~~~~</p>
<img src="" src="https://c-ssl.duitang.com/uploads/item/201803/14/20180314090645_gprdv.jpg" alt="">
</div>
</div>
</body>
js代碼
<script>
var imgArr = document.querySelectorAll('img');
var n = 0; //存儲圖檔加載到的位置,避免每次都從第一張圖檔開始周遊
// 圖檔懶加載
function lazyLoad() {
// 可視區域高度
const seeHeight = window.innerHeight
for (var i = n; i < imgArr.length; i++) {
if (imgArr[i].offsetTop < seeHeight + window.pageYOffset) {
if (imgArr[i].getAttribute('src') == '') {
imgArr[i].src = imgArr[i].getAttribute('data-src')
}
n = i + 1
}
}
}
lazyLoad()
// 滾屏函數
window.onscroll = throttling(lazyLoad)
// 節流函數
function throttling(callback, delay = 1000) {
let timer = null
return function () {
if (timer) return
timer = setTimeout(() => {
callback()
timer = null
}, delay)
}
}
</script>
效果如下:
