防抖跟节流分不清?
一张图解释:
函数防抖
在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。(也就是直到不再触发一段时间后才触发)
运用场景:频繁触发按钮点击事件、input框搜索等等。
function debounce(func, delay) {
let timer = null; // 计时器
return function() {
let context = this;
let args = arguments;
clearTimeout(timer); // 清除上一次计时器
timer = setTimeout(() => { // 重新定时
func.apply(context, args);
}, delay);
};
}
这里涉及到闭包以及改变this指向
闭包:这里简单的可以概括:一个函数中包含着一个函数,但是return的函数外部的代码只会执行一次,执行一次后就存入了闭包,而return的函数实际上就是debounce函数本身,每次进入的时候先找到闭包里的timer,如果找不到再去全局找,这就是闭包的一个用处(个人理解)。
为什么要重新命名this以及arguments?
首先要了解apply()和call()都是每个函数或对象都拥有的非继承的方法。
首先想很好理解和应用apply,其根本是对于this的理解。
this的三种指向:1.指向this所在函数的直接调用者,2.new的时候,指向new出来的对象,3.事件中指向当前的出发对象
这里如果要调用传过来的函数func,如果没有重新定义指向,this就会指向全局而不是func函数本身。
同时为什么要重新定义arguments?
因为func函数本身可能要接受参数,arguments就是传入的参数数组,而且个数可以不确定的传回给func。这样this跟要传给func的参数就不会分不清。
这时候再分析debounce函数的防抖原理:
进入debounce函数,定义一个计时器并保存到闭包,
定义this跟arguments,清除timer也就是让timer变null,延时执行函数func,如果多次触发,就会多次清除定时器(因为timer已经存入闭包(因为不是写在return的函数内部,且在全局打印不到),就不会重新定义(闭包的好处),就不会出现触发多次就延时执行多次的情况),直到不再触发delay时间后再执行func函数。
如何在vue中封装并使用
在units中暴露函数
export function debounce(func, wait) {
let delay = wait || 500;
let timer = null;
return () => {
let contect = this;
let args = arguments;
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(contect, args)
}, delay)
}
}
在需要的vue页面中引入
<button @click="change()">按钮</button>
import { debounce } from "@/utils/index.js";
methods: {
change: debounce(() => {
console.log(1231322);
}, 1000),
}
还有一种更简单的方法:
<button @click="change()">按钮</button>
export default {
data() {
return{
timeout: null
}
},
method: {
change() {
if(this.timeout){
clearTimeout(this.timeout)
}
this.timeout = setTimeout(() => {
console.log(1323)
}, 500);
}
}
}
函数节流:规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。
运用场景:下拉加载更多(无限滚动)事件、浏览器的resize,scroll事件等等
function throttle(func,delay){
let timer;
let wait = delay || 1000;
return function(){
let context = this;
let arg = arguments;
if(timer){ //如果这时候timer有值了则返回,直到delay毫秒后再触发执行。
return;
}
timer = setTimeout(()=>{
func.apply(context, arguments)
timer = null; //这里不用使用clearTimeout,因为这个是在执行完函数后直接清除
},wait)
}
}
节流原理:
从上面代码可以看出,进入throttle先进行对timer进行初始化,第一次进入是没有timer的,所以直接延时执行函数,例如1000毫秒后,执行完函数,则清除timer。若触发throttle的指令还在触发,就会重新延时执行。所以节流就是如果一直触发(例如十秒内触发了一百次,但只会执行十次)。
至于在vue封装则跟防抖的一样
<button @click="change()">按钮</button>
export default {
data() {
return{
timeout: null
}
},
method: {
change() {
if (this.timeout) {
return
}
this.timeout = setTimeout(() => {
console.log(123456);
this.timeout = null
}, 1000);
},