目錄
1. 防抖 節流
2. 預加載
3. 懶加載
(一)防抖 節流
1. 防抖
對於短時間內連續觸發的事件(如滾動事件),防抖的含義就是讓某個時間期限(如上面的1000毫秒)內,事件處理函數只執行一次。
防抖實現思路:在第一次觸發事件時,不立即執行函數,而是給出一個期限值比如200ms,然後:
- 如果在200ms內沒有再次觸發滾動事件,那麼就執行函數
- 如果在200ms內再次觸發滾動事件,那麼當前的計時取消,重新開始計時
效果:如果短時間內大量觸發同一事件,只會執行一次函數。
實現:既然前面都提到了計時,那實現的關鍵就在於setTimeOut這個函數,由於還需要一個變量來保存計時,考慮維護全局純淨,可以藉助閉包來實現:
/*
* fn [function] 需要防抖的函數
* delay [number] 毫秒,防抖期限值
*/
function debounce(fn, delay) {
let timer = null;
return function() {
if (timer) {
claerTimeout(timer)
}
timer = setTimeout(fn, delay)
}
}
2. 節流
效果:如果短時間內大量觸發同一事件,那麼在函數執行一次之後,該函數在指定的時間期限內不再工作,直至過了這段時間才重新生效
function throttle(fn, delay) {
let valid = true;
return function() {
if (!valid) { //valid = false,休息時間,不執行
return false
}
valid = false
setTimeout(() => {
fn()
valid = true;
}, delay)
}
}
(二)預加載
1. 什麼是預加載?
圖片等靜態資源在使用前提前請求,資源後續使用可以直接從緩存中加載。
2. 爲什麼使用預加載?
在網頁全部加載之前,對一些主要內容進行加載,以提供給用戶更好的體驗,減少等待的時間。否則,如果一個頁面的內容過於龐大,沒有使用預加載技術的頁面就會長時間的展現爲一片空白,直到所有內容加載完畢。但預加載會增加服務器的負擔。
3. 實現預加載的方法
-
單純的js預加載圖片
var images = new Array() function preload() { for (let i = 0; i < preload.arguments.length; i++) { images[i] = new Image() images[i].src = preload.arguments[i] } } preload( "http://domain.tld/gallery/image-001.jpg", "http://domain.tld/gallery/image-002.jpg", "http://domain.tld/gallery/image-003.jpg" )
-
使用ajax實現預加載
window.onload = function() { setTimeout(function() { // XHR to request a JS and a CSS var xhr = new XMLHttpRequest(); xhr.open('GET', 'http://domain.tld/preload.js'); xhr.send(''); xhr = new XMLHttpRequest(); xhr.open('GET', 'http://domain.tld/preload.css'); xhr.send(''); // preload image new Image().src = "http://domain.tld/preload.png"; }, 1000); };
(三)懶加載
1. 什麼是懶加載?
懶加載也就是延遲加載。簡單的來說,只有當圖片出現在瀏覽器的可視區域內時,才設置圖片正真的路徑,讓圖片顯示出來。
2. 爲什麼使用懶加載?
對於圖片過多的場景,爲了提高頁面的加載速度,很多時候我們需要將頁面內未出現在可視區域內的圖片先不做加載, 等到滾動到可視區域後再去加載。這樣子對於頁面加載性能上會有很大的提升,也提高了用戶體驗。
懶加載的主要目的是作爲服務器前端的優化,降低服務器的負載,減少請求數或延遲請求數。
3. 懶加載原理
將頁面中的img標籤src指向一張小圖片或者src爲空,然後自定義data-src
屬性指向真實的圖片。當載入頁面時,先把可視區域內的img標籤的data-src
屬性值賦給src
,然後監聽滾動事件,把用戶即將看到的圖片加載。這樣便實現了懶加載。
加載條件:
img.offsetTop < window.innerHeight + document.body.scrollTop;
關於頁面寬高的資料:
4. 實現:
學習並摘自:實現圖片懶加載(lazyload)
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
img {
display: block;
margin-bottom: 50px;
width: 400px;
height: 400px;
}
</style>
</head>
<body>
<img src="default.jpg" data-src="http://ww4.sinaimg.cn/large/006y8mN6gw1fa5obmqrmvj305k05k3yh.jpg" alt="">
<img src="default.jpg" data-src="http://ww4.sinaimg.cn/large/006y8mN6gw1fa5obmqrmvj305k05k3yh.jpg" alt="">
<img src="default.jpg" data-src="http://ww1.sinaimg.cn/large/006y8mN6gw1fa7kaed2hpj30sg0l9q54.jpg" alt="">
<img src="default.jpg" data-src="http://ww1.sinaimg.cn/large/006y8mN6gw1fa7kaed2hpj30sg0l9q54.jpg" alt="">
<img src="default.jpg" data-src="http://ww4.sinaimg.cn/large/006y8mN6gw1fa5obmqrmvj305k05k3yh.jpg" alt="">
<img src="default.jpg" data-src="http://ww4.sinaimg.cn/large/006y8mN6gw1fa5obmqrmvj305k05k3yh.jpg" alt="">
<img src="default.jpg" data-src="http://ww4.sinaimg.cn/large/006y8mN6gw1fa5obmqrmvj305k05k3yh.jpg" alt="">
<img src="default.jpg" data-src="http://ww4.sinaimg.cn/large/006y8mN6gw1fa5obmqrmvj305k05k3yh.jpg" alt="">
<img src="default.jpg" data-src="http://ww1.sinaimg.cn/large/006y8mN6gw1fa7kaed2hpj30sg0l9q54.jpg" alt="">
<img src="default.jpg" data-src="http://ww4.sinaimg.cn/large/006y8mN6gw1fa5obmqrmvj305k05k3yh.jpg" alt="">
<img src="default.jpg" data-src="http://ww4.sinaimg.cn/large/006y8mN6gw1fa5obmqrmvj305k05k3yh.jpg" alt="">
</body>
JavaScript:
<!-- 純js -->
<script>
var imgs = document.getElementsByTagName("img");
var num = imgs.length;
var n = 0; //存儲圖片加載到的位置,避免每次都從第一張圖片開始遍歷
lazyload(); //頁面載入完畢加載可是區域內的圖片
window.onscroll = lazyload;
function lazyload() { //監聽頁面滾動事件
var seeHeight = document.documentElement.clientHeight; //可見區域高度
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop; //滾動條距離頂部高度
for (var i = n; i < num; i++) {
if (imgs[i].offsetTop < seeHeight + scrollTop) {
if (imgs[i].getAttribute("src") == "default.jpg") {
imgs[i].src = imgs[i].getAttribute("data-src");
}
n = i + 1;
}
}
}
</script>
JQuery:
<script>
var n = 0,
imgNum = $("img").length,
img = $('img');
lazyload();
$(window).scroll(lazyload);
function lazyload(event) {
for (var i = n; i < imgNum; i++) {
if (img.eq(i).offset().top < parseInt($(window).height()) + parseInt($(window).scrollTop())) {
if (img.eq(i).attr("src") == "default.jpg") {
var src = img.eq(i).attr("data-src");
img.eq(i).attr("src", src);
n = i + 1;
}
}
}
}
</script>
如果直接將函數綁定在scroll
事件上,當頁面滾動時,函數會被高頻觸發,這非常影響瀏覽器的性能。
下面實現限制觸發頻率,來優化性能。
使用節流函數進行性能優化:
// 簡單的節流函數
//fun 要執行的函數
//delay 延遲
//time 在time時間內必須執行一次
function throttle (fun, delay, time) {
let timeout
let startTime = new Date()
return function () {
let context = this
let args = Array.prototype.slice.call(arguments)
let curTime = new Date()
clearTimeout(timeout)
if (curTime - startTime >= time) {
// 如果達到了規定的觸發時間間隔,觸發 handler
fun.apply(context, args)
startTime = curTime
} else {
// 沒達到觸發間隔,重新設定定時器
timeout = setTimeout(function () {
fun.apply(context, args)
}, delay)
}
}
};
// 實際想綁定在 scroll 事件上的 handler
function lazyload(event) {}
// 採用了節流函數
window.addEventListener('scroll',throttle(lazyload,500,1000));
使用防抖函數進行性能優化
防抖相比較節流函數要稍微簡單一點,防抖是讓函數延遲執行,而節流比防抖多了一個在一定時間內必須要執行一次。
// debounce函數用來包裹我們的事件
function debounce (fn, delay) {
// 持久化一個定時器 timer
let timer = null
// 閉包函數可以訪問 timer
return function () {
// 通過 'this' 和 'arguments'
// 獲得函數的作用域和參數
let context = this
let args = Array.prototype.slice.call(arguments)
// 如果事件被觸發,清除 timer 並重新開始計時
clearTimeout(timer)
timer = setTimeout(function () {
fn.apply(context, args)
}, delay)
}
}
// 實際想綁定在 scroll 事件上的 handler
function lazyload(event) {}
// 採用了去抖函數
window.addEventListener('scroll',debounce(lazyload,500));