前言
瀏覽器中某些計算和處理要比其他的昂貴很多。例如DOM操作比DOM交互需要更多的時間和cpu時間,為了提升性能呕屎,減少DOM操作,于是敬察,函數(shù)節(jié)流防抖和應(yīng)運而生秀睛,其函數(shù)節(jié)流的基本思想是指莲祸,某些代碼不可以在沒有間斷的情況下連續(xù)重復(fù)執(zhí)行锐帜。函數(shù)防抖的基本思想是指,一個頻繁觸發(fā)的事情只讓最后一次執(zhí)行瓷式。下面就讓我們來認真了解下這經(jīng)常使用的函數(shù)節(jié)流和防抖。
函數(shù)節(jié)流
函數(shù)節(jié)流:一個函數(shù)執(zhí)行一次后据过,只有大于設(shè)定的執(zhí)行周期后才會執(zhí)行第二次绳锅。有個需要頻繁觸發(fā)函數(shù)期虾,出于優(yōu)化性能角度,在規(guī)定時間內(nèi)壕鹉,只讓函數(shù)觸發(fā)的第一次生效牛郑,后面不生效钉答。
下面主要介紹時間戳和定時器兩種方式來實現(xiàn)節(jié)流函數(shù)仑性。
- 時間戳實現(xiàn)函數(shù)節(jié)流
根據(jù)函數(shù)節(jié)流的原理,我們也可以不依賴 setTimeout
實現(xiàn)函數(shù)節(jié)流。
function throttle(fn, delay) {
// 記錄上一次函數(shù)觸發(fā)的時間
var lastTime = 0;
return function() {
// 記錄當(dāng)前函數(shù)觸發(fā)的時間
var nowTime = Date.now();
if (nowTime - lastTime > delay) {
// 修正this指向問題
fn.call(this);
// 同步時間
lastTime = nowTime;
}
}
}
測試代碼:
// test
function testThrottle(e, content) {
console.log(e, content);
}
var testThrottleFn = throttle(testThrottle, 1000); // 節(jié)流函數(shù)
document.onmousemove = function (e) {
testThrottleFn(e, 'throttle'); // 給節(jié)流函數(shù)傳參
}
其實現(xiàn)原理钠怯,通過比對上一次執(zhí)行時間與本次執(zhí)行時間的時間差與間隔時間的大小關(guān)系晦炊,來判斷是否執(zhí)行函數(shù)。若時間差大于間隔時間宁脊,則立刻執(zhí)行一次函數(shù)断国。并更新上一次執(zhí)行時間。
- 定時器實現(xiàn)函數(shù)節(jié)流
function throttle(fn, delay) {
var timer;
return function () {
var _this = this;
var args = arguments;
if (timer) {
return;
}
timer = setTimeout(function () {
fn.apply(_this, args);
timer = null; // 在delay后執(zhí)行完fn之后清空timer朦佩,此時timer為假并思,
throttle觸發(fā)可以進入計時器
}, delay)
}
}
測試代碼:
function testThrottle(e, content) {
console.log(e, content);
}
var testThrottleFn = throttle(testThrottle, 2000); // 節(jié)流函數(shù)
document.onmousemove = function (e) {
testThrottleFn(e, 'throttle'); // 給節(jié)流函數(shù)傳參
}
上面例子中,如果我們一直在瀏覽器中移動鼠標(比如10s
)语稠,則在這10s
內(nèi)會每隔2s
執(zhí)行一次testThrottle
宋彼,這就是函數(shù)節(jié)流。
函數(shù)節(jié)流的目的仙畦,是為了限制函數(shù)一段時間內(nèi)只能執(zhí)行一次输涕。因此,定時器實現(xiàn)節(jié)流函數(shù)通過使用定時任務(wù)慨畸,延時方法執(zhí)行莱坎。在延時的時間內(nèi),方法若被觸發(fā)寸士,則直接退出方法檐什。從而,實現(xiàn)函數(shù)一段時間內(nèi)只執(zhí)行一次弱卡。
函數(shù)節(jié)流的應(yīng)用場景
需要間隔一定時間觸發(fā)回調(diào)來控制函數(shù)調(diào)用頻率:
-
DOM
元素的拖拽功能實現(xiàn)(mousemove) - 搜索聯(lián)想(keyup)
- 計算鼠標移動的距離(mousemove)
-
Canvas
模擬畫板功能(mousemove) - 滾動加載乃正,加載更多或滾到底部監(jiān)聽
- 谷歌搜索框,搜索聯(lián)想功能
- 高頻點擊提交婶博,表單重復(fù)提交
函數(shù)防抖
防抖函數(shù):一個需要頻繁觸發(fā)的函數(shù)瓮具,在規(guī)定時間內(nèi),只讓最后一次生效,前面的不生效名党。
function debounce(fn, delay) {
var timer = null;
return function () {
var _this = this; // 取debounce執(zhí)行作用域的this
var args = arguments;
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(function () {
fn.apply(_this, args); // 用apply指向調(diào)用debounce的對象叹阔,
相當(dāng)于_this.fn(args);
}, delay);
};
}
測試代碼:
function testDebounce(e, content) {
console.log(e, content);
}
var testDebounceFn = debounce(testDebounce, 1000); // 防抖函數(shù)
document.onmousemove = function (e) {
testDebounceFn(e, 'debounce'); // 給防抖函數(shù)傳參
}
上面例子中的debounce
就是防抖函數(shù),在document
中鼠標移動的時候传睹,會在onmousemove
最后觸發(fā)的1s
后執(zhí)行回調(diào)函數(shù)testDebounce
耳幢;如果我們一直在瀏覽器中移動鼠標(比如10s
),會發(fā)現(xiàn)會在10+1s
后才會執(zhí)行testDebounce
函數(shù)(因為clearTimeout(timer)
)蒋歌,這個就是函數(shù)防抖帅掘。
函數(shù)防抖的應(yīng)用場景
對于連續(xù)的事件響應(yīng)我們只需要執(zhí)行一次回調(diào):
- 每次 resize/scroll 觸發(fā)統(tǒng)計事件
- 文本輸入的驗證(連續(xù)輸入文字后發(fā)送 AJAX 請求進行驗證,驗證一次就好)
- 搜索框搜索輸入堂油。只需用戶最后一次輸入完修档,再發(fā)送請求
- 手機號、郵箱驗證輸入檢測
- 窗口大小Resize府框。只需窗口調(diào)整完成后吱窝,計算窗口大小。防止重復(fù)渲染迫靖。
總結(jié)
函數(shù)節(jié)流和函數(shù)去抖的核心其實就是限制某一個方法被頻繁觸發(fā)院峡,其目的都是,降低回調(diào)執(zhí)行頻率系宜,節(jié)省計算資源照激,提高瀏覽器的性能。
更多優(yōu)質(zhì)文章可以訪問GitHub博客盹牧,歡迎帥哥美女前來StarA├!汰寓!