JS函数的节流和防抖
防抖(debounce): 触发事件后在n秒内函数只能执行一次,如果在n秒内又触发了事件,则会重新计算函数执行事件
非立即执行版本:触发事件后函数不会立即执行,而是在n秒后执行,如果在n秒内触发了事件则会重新计算函数执行时间。
/* 函数防抖 */
var inputDom = document.querySelectorAll("#debounce")[0];
/* 非立即执行防抖 */
var timer = null;
inputDom.addEventListener("input", function(){
clearTimeout(timer);
var self = this;
var arg = arguments;
clearTimeout(timer);
timer = setTimeout(function(){
//此处不能使用call,应该使用apply,直接将参数放在数组中传
handle.apply(this, arg);
}, 800)
});
function handle(ev){
var ev = ev || window.event;
console.log("ev:", ev);
}
/* 封装 */
function debounce(func, wait){
let timer = null;
return (function(){
let self = this;
let args = arguments;
if(timer) clearTimeout(timer);
timer = setTimeout(() => {
func.apply(self, args)
}, wait);
})
}
立即执行版本: 触发事件后函数会立即执行,然后n秒内不触发事件才能继续执行函数的效果。
/* 立即执行防抖 */
var inputDom = document.querySelectorAll("#debounce")[0];
var timer;
inputDom.addEventListener("input", function(){
if(timer) clearTimeout(timer);
// 判断是否在等待时间内
var callNow = !timer;
timer = setTimeout(() => {
// 等待一段时间后重置timer
timer = null
}, 1000);
// 如果不在等待时间内,则调用事件处理函数
if(callNow) handle.apply(this, arguments);
});
function handle(ev){
var ev = ev || window.event;
console.log("ev:", ev);
}
/* 封装版本 */
function debounce(handle, wait){
let timer;
return (function(){
let self = this, args = arguments;
if(timer) clearTimeout(timer);
let callNow = !timer;
timer = setTimeout(() => {
timer = null;
}, 1000);
if(callNow){
handle.apply(self, args);
}
});
}
双剑合璧版本:
/**
* @desc 函数防抖
* @param func 函数
* @param wait 延迟执行毫秒数
* @param immediate true 表立即执行,false 表非立即执行
*/
function debounce(func,wait,immediate) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout);
if (immediate) {
var callNow = !timeout;
timeout = setTimeout(() => {
timeout = null;
}, wait)
if (callNow) func.apply(context, args)
}
else {
timeout = setTimeout(function(){
func.apply(context, args)
}, wait);
}
}
}
节流(throttle):指连续触发事件但是在n秒中只执行一次函数。节流会稀释函数的执行频率。
时间戳版本:
/* 节流 */
/* 时间戳版本 */
var inputDom = document.querySelectorAll("#debounce")[0];
var previous = 0;
inputDom.addEventListener("input", function(){
var now = Date.now();
if(now - previous > 1000){
handle.apply(this, arguments);
// 重置时间戳
previous = now;
}
});
function handle(ev){
var ev = ev || window.event;
console.log("ev:", ev);
}
/* 封装版本 */
function throttle(handle, wait){
let previous = 0;
return (function(){
let now = new Date();
let context = this;
let args = arguments;
if(now - previous){
handle.apply(context, args);
previous = now;
}
})
}
定时器版本:
/* 封装版本 */
function throttle(handle, wait){
let timeout;
return (function(){
let context = this;
let args = arguments;
if(!timeout){
timeout = setTimeout(() => {
timer = null;
handle.apply(context, args);
}, wait)
}
});
}
时间戳版和定时器版的节流函数的区别是:时间戳版的函数触发是在时间段内开始的时候,而定时器版的函数触发是在时间段内结束的时候。
双剑合璧版本:
/**
* @desc 函数节流
* @param func 函数
* @param wait 延迟执行毫秒数
* @param type 1 表时间戳版,2 表定时器版
*/
function throttle(func, wait ,type) {
if(type===1){
let previous = 0;
}else if(type===2){
let timeout;
}
return function() {
let context = this;
let args = arguments;
if(type===1){
let now = Date.now();
if (now - previous > wait) {
func.apply(context, args);
previous = now;
}
}else if(type===2){
if (!timeout) {
timeout = setTimeout(() => {
timeout = null;
func.apply(context, args)
}, wait)
}
}
}
}

浙公网安备 33010602011771号