防抖和节流的目的都是为了减少不必要的计算,不浪费资源,只在适合的时候再进行触发计算。
一、函数防抖(debounce)
1.定义: 事件触发停止一定时间后才会执行响应的函数,期间如果重复调用动作,重新计算时间。类似于,按下一个弹簧,只有你松手的时候弹簧才会弹起。本质上是将多次操作合并为一次操作。可用一个定时器维护,事件触发后wait时间内如果事件重复触发,那么取消当前定时器,重新设置一个时延为wait的定时器。
2.实现原理
函数防抖的基本思想是设置一个定时器,在指定时间间隔内运行代码时清除上一次的定时器,并设置另一个定时器,直到函数请求停止并超过时间间隔才会执行。
3.使用场景
文本框输入搜索(连续输入时避免多次请求接口)
4.代码实现
/**
* 函数防抖
*/
export function debounce(fn, t) {
// 记录上一次的延时器
var timer = null;
var delay = t || 200;
return function() {
var args = arguments;
var that = this;
// 清除上一次延时器
clearTimeout(timer)
timer = setTimeout(function() {
fn.apply(that,args)
}, delay);
}
}
二、函数节流
1.定义
规定在一个单位时间内,只能触发一次函数,如果这个单位时间内触发多次函数,只有一次生效; 典型的案例就是鼠标不断点击触发,规定在n秒内多次点击只有一次生效。
2.实现原理
其原理是用时间戳来判断是否已到回调该执行时间,记录上次执行的时间戳,然后每次触发 scroll 事件执行回调,回调中判断当前时间戳距离上次执行时间戳的间隔是否已经到达 规定时间段,如果是,则执行,并更新上次执行的时间戳。
3.使用场景
resize、scroll、mousemove等事件触发监听
4.代码实现
/**
* 函数节流
*/
export function throttle(fn,t){
var lastTime;
var timer;
var delay = t || 200;
return function() {
var args = arguments;
// 记录当前函数触发的时间
var nowTime = Date.now();
if (lastTime && nowTime - lastTime < delay) {
clearTimeout(timer);
timer = setTimeout(function () {
// 记录上一次函数触发的时间
lastTime = nowTime;
// 修正this指向问题
fn.apply(this, args);
}, delay);
}else{
lastTime = nowTime;
fn.apply(this, args);
}
}
}
函数防抖节流在Vue中的使用。
1.在libs文件夹下创建public.js文件
完整代码如下:
/**
* 函数防抖
*/
export function debounce (fn, t) {
// 记录上一次的延时器
var timer = null
var delay = t || 200
return function () {
var args = arguments
var that = this
// 清除上一次延时器
clearTimeout(timer)
timer = setTimeout(function () {
fn.apply(that, args)
}, delay)
}
}
/**
* 函数节流
*/
export function throttle (fn, t) {
var lastTime
var timer
var delay = t || 200
return function () {
var args = arguments
// 记录当前函数触发的时间
var nowTime = Date.now()
if (lastTime && nowTime - lastTime < delay) {
clearTimeout(timer)
timer = setTimeout(function () {
// 记录上一次函数触发的时间
lastTime = nowTime
// 修正this指向问题
fn.apply(this, args)
}, delay)
} else {
lastTime = nowTime
fn.apply(this, args)
}
}
}
2.在你需要的页面中引用
import { throttle,debounce } from '@/libs/public.js'
3.在组件中使用
<template>
<li
class="content-box"
v-for="(list,index) in filterData"
:key="index"
@click="changeColor2(list,index)"
>
</li>
</template>
methods: {
changeColor2: throttle(function(list,index) {
//do something
},100)
}
解释一下:throttle是引用了节流这个函数,在function(list,index)里面可以传递参数,100是以毫秒为单位的时间
原生使用
函数防抖
当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时。如下面这段代码,持续触发scroll事件时,并不执行handle函数,当1000毫秒内没有触发scroll事件时,才会延时触发scroll事件。
一个防抖的例子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
body{
height: 5000px;
}
</style>
</head>
<body>
<script>
//防抖函数、fn(处理函数),wait(自定义定时器时间)
function debounce(fn, wait) {
var timeout = ""; //声明变量timeout复制为空字符串
return function() {//返回匿名函数
if(timeout !== ""){//如果timeout不为空
clearTimeout(timeout);//清除timeout定时器
}
timeout = setTimeout(fn, wait);//重新给timeout赋值为fn我处理函数,wait为定时周期的一次性定时器
}
}
// 处理函数
function handle() {
console.log(Math.random());
}
// 滚动事件
window.addEventListener('scroll', debounce(handle, 1000));//为window的scroll滑动事件绑定防抖函数
</script>
</body>
</html>
代码执行路线是:
1、页面初始化,渲染页面,执行代码
2、调用debounce函数,声明一个变量timeout,并赋值为空字符串。返回一个匿名函数,通过addEventListener绑定给window的scroll(滑动事件)
3、触发window的scroll(滑动事件)
4、进入window的scroll的处理函数(调用debounce函数返回的那个匿名函数)。
5.1、如果timeout不为空,清除timeout定时器,重新给timeout赋值为fn我处理函数,wait为定时周期的一次性定时器。
5.2、如果timeout为空,重新给timeout赋值为fn我处理函数,wait为定时周期的一次性定时器。
6、再次触发window的scroll(滑动事件),重复步骤4和步骤5
7、停止触发,执行一遍步骤4和步骤5
8、执行timeout一次性定时器,调用handle函数进行处理
函数节流------》定时器+时间戳
所以我们就把事件戳的有点和定时器的有点结合起来,变成下面的方案
var throttle = function(func, delay) {
var timer = "";
var startTime = Date.now();
return function() {
var curTime = Date.now();
var remaining = delay - (curTime - startTime);
var context = this;
var args = arguments;
clearTimeout(timer);
if (remaining <= 0) {
func.apply(context, args);
startTime = Date.now();
} else {
timer = setTimeout(func, remaining);
}
}
}
function handle() {
console.log(Math.random());
}
window.addEventListener('scroll', throttle(handle, 1000));