JS 節流閥
節流閥
節流閥的基本原理
事件函數的執行都記下當前時間, 只有當前時間與上次執行時間有一定間隔的時候才會去執行真正的邏輯
function throttleMe(cb){
console.log('move');
var start = +new Date();
return function(){
var now = new Date();
if(now - start > 1000){
start = now;
cb();
}
}
}
$(window).on('mousemove', throttleMe(function(){
console.log('timer');
}));
有的書上是這么實現的 這個並不好用
var resizeTimer = null;
$(window).on('mousemove', function (e) {
console.log('move');
/* 第一次訪問,不存在 resizeTimer,跳過這里 */
if (resizeTimer) {
clearTimeout(resizeTimer);
}
/* 第一次訪問,賦值給 resizeTimer,綁定的函數 400ms 后調用 */
resizeTimer = setTimeout(function(){
console.log("move timer" /*+ e.clientX + '-' + e.clientY*/ );
}, 40);
});
發現實際中並不是40ms調用一次move timer
原因就在於timeout 它是等這個函數執行完之后間隔40ms 才有機會去執行下一個函數
function throttle(func, wait) {
var context, args, timeout, result;
var previous = 0;
var later = function() {
previous = +new Date();
timeout = null;
result = func.apply(context, args);
};
return function() {
var now = +new Date();
var remaining = wait - (now - previous); //距離下次執行剩余時間
console.log('remaining'+remaining + 'now'+ now);
context = this;
args = arguments;
if (remaining <= 0) { //過了間隔時間段 開始執行
clearTimeout(timeout);
timeout = null;
previous = now;
console.log('<0<0<0');
result = func.apply(context, args);
} else if (!timeout) {
console.log('set time out------------');
timeout = setTimeout(later, remaining);
}
return result;
};
}
函數去抖
function debounce(fn, threshhold, scope) {
threshhold || (threshhold = 250);
var last,
deferTimer;
return function() {
console.log('move');// 這個函數是mousemove事件處理的函數
var context = scope || this;
var now = +new Date,
args = arguments;
if (last && now < last + threshhold) {
// hold on to it
clearTimeout(deferTimer);
deferTimer = setTimeout(function() {
last = now;
fn.apply(context, args);
}, threshhold);
} else {
last = now;
fn.apply(context, args);
}
};
}
$('body').on('mousemove', function() {
console.log('move');
});
$('body').on('mousemove', debounce(function(event) {
console.log('tick');
}, 1000));
每次mousemove都是在執行 debounce返回的一個函數
這個返回的函數用到了debounce中的一個變量last
奇怪! 這個last 又不是全局的變量 為什么這個函數每次執行都依賴上次last的結果? 因為這里是一個閉包
通過閉包 使局部變量變成全局變量
因為這個a后面一直被fun函數使用 所以這個變量不會被銷毀 正是閉包特性
function closure(){
var a = 1;
return function(){
return ++a;
}
}
fun = closure();
console.log(fun());//2
console.log(fun());//3
console.log(fun());//4