函数防抖和节流是用来干什么的?
- 是优化高频率执行js代码一种手段。
- 在js中有一些事件在触发时会不断调用绑定在事件上的回掉函数,极大地浪费资源,降低性能。
- 上述事件有resize、scroll、mousemove、mouseover、input输入框的keypress事件等
- 所以为了优化体验,需要对这类事件进行调用次数的限制。
1. 防抖
定义:
指触发事件后在n秒内函数只执行一次,如果在n秒内又触发事件,则会重新计算函数执行时间
(计时清零)
防抖分为非立即执行版和立即执行版。
- 所谓非立即执行就是触发事件后,函数不会立即执行,而是在n秒后执行,如果在n秒内又触发了事件,则会重新计算函数执行时间(即延迟执行)
代码如下:
function debounce(func, wait){
let timer;
return function(){
let _this = this;
let args = arguments;
if(timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
func.apply(_this, args);
}, wait)
}
}
- 立即执行就是触发事件后函数会立即执行,执行后的n(s)内忽略后续触发
代码如下:
function debounce(func,wait){
let timer;
return function(){
let _this = this;
let args = arguments;
if(timer){
clearTimeout(timer);
}
let callNow = !timer;
timer = setTimeout(() => {
timer = null;
}, wait)
if(callNow){
func.apply(_this,args);
}
}
}
- 在开发的过程中我们需要根据不同的场景来决定使用哪种防抖函数。结合版代码如下
// immediate 表示是否立即执行
function debounce(func,wait,immediate){
let timer;
return function(){
let _this = this;
let args = arguments;
if(timer) {
clearTimeout(timer);
}
if(immediate) {
let callNow = !timer;
timer = setTimeout(() => {
timer = null;
}, wait);
if(callNow){
func.apply(_this,args);
}
} else {
timer = setTimeout(() => {
func.apply(_this, args);
}, wait)
}
}
}
2. 节流(throttle)
定义:
节流是指连续触发事件在n秒中只执行一次。
节流的两种实现方式:
- 时间戳版(立即执行)
- 函数是在时间段开始时候执行
代码如下:
function throttle(func,wait){
let previous = 0; // 执行代码时的时间
return function(){
let now = Date.now(); // 触发事件时的时间
let _this = this;
let args = arguments;
if(now - previous > wiat) {
func.apply(_this,args);
previous = now;
}
}
}
- 定时器版(非立即执行)
- 函数是在时间段结束后执行
代码如下:
function throttle(func,wait){
let timer;
return function(){
let _this = this;
let args = arguments;
if(!timer){
timer = setTiment(() => {
timer = null;
func.apply(_this, args)
}, wait)
}
}
}
依然结合两种方式整合函数节流,代码如下:
// type=1时间戳版 type=2定时器版
function throttle(func,wait,type){
if(type === 1){
var previous = 0; // 注意:这儿使用var而不使用let的原因是let会形成块级作用域,外面访问不到
} else if(type === 2) {
var timer;
}
return function(){
let _this = this;
let args = arguments;
if(type === 1){
let now = Date.now();
if(now - previous > wait) {
func.apply(_this,args);
previous = now;
}
}else if(type === 2) {
if(!timer) {
timer = setTimeout(() => {
timer = null;
func.apply(_this,args);
},wait)
}
}
}
}