js網絡請求性能優化之防抖與節流


一丶基本概念

防抖(debounce):在函數需要頻繁觸發時,只有當有足夠空閑的時間時,才執行一次。就好像在百度搜索時,每次輸入之后都有聯想詞彈出,這個控制聯想詞的方法就不可能是輸入框內容一改變就觸發的,他一定是當你結束輸入一段時間之后才會觸發。

節流(thorttle):預定一個函數只有在大於等於執行周期時才執行,周期內調用不執行。就好像你在淘寶搶購某一件限量熱賣商品時,你不斷點刷新點購買,可是總有一段時間你點上是沒有效果,這里就用到了節流,就是怕點的太快導致系統出現bug。

區別:在發生持續觸發事件時,防抖設置事件延遲並在空閑時間去觸發事件,而節流則是隔一定的時間觸發一次。

二丶函數防抖

函數防抖運用的實際場景有:實時搜索,拖拽,登錄用戶名密碼格式驗證等等。

實現函數防抖的關鍵就是對setTimeout()這個方法的運用。先以實時搜索為例分析一下。

首先我們要寫一個監聽函數用來監聽搜索框的value的變化。

var oInp;// 假設在此取得輸入框
oInp.oninput = ajax;
// 模擬ajax請求后台數據
function ajax() {
console.log(this.value);// 搜索框value值
}
寫完之后我們會發現每當我們輸入一個單詞,即每當搜索框內容發生變化時都會觸發我們的監聽函數來請求后台數據,如此頻繁的請求肯定不是我們想要的,所以我們就需要稍加處理一下,使其不再一改變就觸發,而是當我們輸完之后再觸發發送請求。針對這種需求我們可以使用防抖來實現。

var oInp;// 假設在此取得輸入框
var timer = null; // 定義一個全局定時器
oInp.oninput = function(e) {
clearTimeout(timer);
timer = setTimeout(function(){
ajax();
}, 1000);
};
// 模擬ajax請求后台數據
function ajax() {
console.log(this.value);// 搜索框value值
}
這個整體的實現思想就是,當搜索框內容發生改變時,就會觸發一個定時器。但是當搜索框內容再次發生改變時,我們先清除上一個定時器,再重新創建一個定時器。這樣,只有當我們結束輸入,搜索框內容在一定時間內不再發生改變時才會發送請求。

但是上面的代碼塊還有兩個問題,一個就是this的指向,setTimeout()形成了一個閉包,當執行的時候,ajax()方法中的this實際指向window,所以我們還需要進行以下優化,改變this指向。

var oInp;// 假設在此取得輸入框
var timer = null; // 定義一個全局定時器
oInp.oninput = function(e) {
var _this = this;
clearTimeout(timer);
timer = setTimeout(function(){
ajax().apply(_this); // 綁定this
}, 1000);
};
// 模擬ajax請求后台數據
function ajax() {
console.log(this.value);// 搜索框value值
}
第二個問題就是e -- 事件對象,在上面一系列的方法調用之中,e已經被丟了,變成了undefined,所以我們還需要進行以下優化,將事件對象重新找回來。

var oInp;// 假設在此取得輸入框
var timer = null; // 定義一個全局定時器
oInp.oninput = function(e) {
var _this = this,
_arg = arguments; // e
clearTimeout(timer);
timer = setTimeout(function(){
ajax().apply(_this, _arg); // 綁定this, 傳入e
}, 1000);
};
// 模擬ajax請求后台數據
function ajax(e) {
console.log(this.value);// 搜索框value值
console.log(e); // 事件對象
}
 

如上就基本實現了函數防抖。為了實現通用性,在這里將防抖封裝成一個方法,方便之后重復使用。

 

function debounce(handle, delay) {
var timer = null;
return function() {
var _this = this,
_arg = arguments;
clearTimeout(timer);
timer = setTimeout(function() {
handle.apply(_this, _arg);
}, delay);
}
} // 其中 handle 為需要進行防抖操作的函數,delay 為延遲時間
三丶函數節流

函數節流運用的實際場景有:窗口調整,頁面滾動,搶購瘋狂點擊等等。

在這里以瘋狂點擊為例進行分析。

首先寫一個簡單的頁面,當點擊按鈕時,數字不斷增大,模擬搶購按鈕。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="show">0</div>
<button id="btn">點我</button>
<script>
var oDiv = document.getElementById('show'),
oBtn = document.getElementById('btn');
oBtn.onclick = function() {
oDiv.innerHTML = parseInt(oDiv.innerHTML) + 1;
}
</script>
</body>
</html>
我們肯定不希望用戶去瘋狂點擊導致數字不斷增加,甚至是使用惡意腳本去實現瘋狂點擊按鈕

for(var i = 0; i < 1000; i ++) {
oBtn.onclick();
}
所以就要引入一個新思想,那就是在一秒鍾之內無論用戶點多少次,都只算他點了一次,這就是節流的核心思想。

function throttle(handle, wait) {
var lasttime = 0;
return function(e) {
var nowtime = new Date().getTime();
if(nowtime - lasttime > wait) {
handle.apply(this, arguments);
lasttime = nowtime;
}
}
}
function buy() {
oDiv.innerHTML = parseInt(oDiv.innerHTML) + 1;
}
oBtn.onclick = throttle(buy, 1000);
現在分析一下throttle方法。

參數中 handle 為需要進行節流的方法,wait為等待時間。

因為我們需要實現在一定的等待時間wait內不能執行buy()方法,所以首先需要兩個時間戳,一個記錄第一次點擊的時間lasttime,一個記錄當前的時間nowtime,只有當 nowtime 與 lasttime 的時間差大於wait時,才會再次觸發buy(),同時改變lasttime為新時間戳。

放在throttle()中就是首先記錄初始時間為0,當第一次點擊時,獲得現在時間為nowtime,時間差大於wait,執行buy(),然后本次點擊的時間就成了一個新的時間點,下次點擊就需要和這次點擊的時間進行判斷,所以設置當前時間為初始時間,然后下次點擊時繼續判斷。

四丶總結

防抖和節流雖然實現起來不難,但在實際開發中還是很常用的,因為它們可以極大的優化網絡請求性能,提高用戶體驗。
---------------------
作者:jacoox
來源:CSDN
原文:https://blog.csdn.net/jacoox/article/details/80719456
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM