函数节流和函数防抖,两者都是优化高频率执行js代码的一种手段
有时在给DOM绑定事件时,有些事件我们是无法控制触发频率的。 如鼠标移动事件onmousemove, 滚动条事件onscroll,窗口大小改变事件onresize,瞬间的操作都会导致这些事件会被高频触发。 如果事件的回调函数较为复杂,就会导致响应跟不上触发,出现页面卡顿,假死现象。 在实时检查输入时,如果我们绑定onkeyup事件发请求去服务端检查,用户输入过程中,事件的触发频率也会很高,会导致大量的请求发出,响应速度会大大跟不上触发。
针对此类问题,我们可以使用防抖和节流
防抖(debounce)
在一次触发事件后,不立即执行函数,而是给出一个期限值,如200ms,然后
1.如果在200ms内没有再次出发事件,那么就执行函数
2.如果在200ms内再次触发了事件,那么当前的记时取消,重新开始计时
**效果:**如果在短时间内大量的触发同一事件,只会执行一次函数
应用: 1.search搜索联想,用户在不断输入值时,用防抖来节约请求资源。
2.window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次
//实现
一、非立即执行
function debounce(fn, wait) {
var timeout = null; //定义一个定时器
return function() {
if(timeout !== null){
clearTimeout(timeout); //清除这个定时器
}
timeout = setTimeout(fn, wait);
}
}
二、立即执行
function debounce(func,wait) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout);
let callNow = !timeout;
timeout = setTimeout(() => {
timeout = null;
}, wait)
if (callNow) func.apply(context, args)
}
}
节流(thottle)
函数执行一次后,在某个时间段内暂时失效,等过了这段时间后再重新激活
**效果:**如果短时间内大量触发同一个事件,那么在函数执行完一次后,该函数在指定时间内不工作,等过了这段时间才重新生效
应用: 1.鼠标不断点击触发,mousedown(单位时间内只触发一次)
2.监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断
实现
一、时间戳
function throttle(func, delay) {
var prev = Date.now();
return function() {
var context = this; //this指向window
var args = arguments;
var now = Date.now();
if (now - prev >= delay) {
func.apply(context, args);
prev = Date.now();
}
}
}
二、定时器
function throttle(func, delay) {
var timer = null;
return function() {
var context = this;
var args = arguments;
if (!timer) {
timer = setTimeout(function() {
func.apply(context, args);
timer = null;
}, delay);
}
}
}
最后,我们把防抖和节流封装一下
//函数防抖封装
/**
* @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);
}
}
}
//函数节流封装
/**
* @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)
}
}
}
}
``