防抖:当持续触发事件时,一定时间内没有再触发事件,才会在一段时间之后触发事件处理函数。
节流:当持续触发事件时,保证一段delay之内,只调用一次函数
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>防抖title>
head>
<body>
<label for='undebounce'>没防抖:label>
<input type="text" id='undebounce' onInput='onInput1(event)' >
<br />
<label for="debounce">有防抖:label>
<input type="text" id='debounce' onInput='debounceInput(event)' >
<script>
function debounce(fn, delay){
let time = null
return function(...args){
if(time){
clearTimeout(time)
}
time = setTimeout(()=>{
fn.apply(this, args)
},delay)
}
}
function onInput(e){
val = e.target.value
if(val){
console.log('有防抖',val)
}
}
const debounceInput = debounce(onInput, 300)
function onInput1(e){
val = e.target.value
if(val){
console.log('没有防抖',val)
}
}
script>
body>
html>
::: tip
- 没有防抖的输入框持续输入时,每键入一个字母都执行一次处理函数
- 有防抖的输入框持续输入时,在键入字母结束之后才执行一次处理函数
:::
首节流,时间戳的实现,首次触发立即执行,停止触发后,没办法再次执行
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>节流throttletitle>
head>
<body>
<ul>
<li>1li>
<li>2li>
<li>3li>
<li>4li>
<li>5li>
<li>6li>
<li>7li>
<li>8li>
<li>9li>
<li>1li>
<li>2li>
<li>3li>
<li>4li>
<li>5li>
<li>6li>
<li>7li>
<li>8li>
<li>9li>
ul>
body>
<style>
body{
display: flex;
justify-content: center;
}
ul, li {
padding:0;
margin: 0;
}
li{
width: 250px;
height:200px;
list-style: none;
display: flex;
justify-content: center;
align-items: center;
}
li:nth-child(2n){
background:whitesmoke;
}
li:nth-child(2n+1){
background:yellow;
}
style>
<script>
// 首节流,时间戳的实现,停止触发后,没办法再次执行
function throttle(fn, interval){
let prev = 0;
return function(...args){
const now = Date.now();
if( now-prev >= interval ){
prev = now
fn.apply(this, args)
}
}
}
function handle(){
console.log(new Date())
}
const throttleHandler = throttle(handle, 3000)
console.log('tt', throttleHandler)
window.addEventListener('scroll', throttleHandler)
script>
html>
可以看到,只要滑动了,就会触发事件,但是停止滑动之后,不会触发最后一次。
定时器实现,不会立即执行,而是在delay之后执行
最后停止触发之后,还会执行一次
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>节流throttletitle>
head>
<body>
<ul>
<li>1li>
<li>2li>
<li>3li>
<li>4li>
<li>5li>
<li>6li>
<li>7li>
<li>8li>
<li>9li>
<li>1li>
<li>2li>
<li>3li>
<li>4li>
<li>5li>
<li>6li>
<li>7li>
<li>8li>
<li>9li>
ul>
body>
<style>
body{
display: flex;
justify-content: center;
}
ul, li {
padding:0;
margin: 0;
}
li{
width: 250px;
height:200px;
list-style: none;
display: flex;
justify-content: center;
align-items: center;
}
li:nth-child(2n){
background:whitesmoke;
}
li:nth-child(2n+1){
background:yellow;
}
style>
<script>
// 尾节流,定时器实现,不会立即执行,而是在delay之后执行
// 最后停止触发之后,还会执行一次
function throttle(fn,delay){
let timer = null
return function(...args){
if( !timer ){
timer = setTimeout(()=>{
fn.apply(this, args)
timer = null
}, delay)
}
}
}
function handle(){
console.log(new Date())
}
const throttleHandler = throttle(handle, 3000)
console.log('tt', throttleHandler)
window.addEventListener('scroll', throttleHandler)
script>
html>
可以看到我们停止滑动之后还是触发了事件
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>节流throttletitle>
head>
<body>
<ul>
<li>1li>
<li>2li>
<li>3li>
<li>4li>
<li>5li>
<li>6li>
<li>7li>
<li>8li>
<li>9li>
<li>1li>
<li>2li>
<li>3li>
<li>4li>
<li>5li>
<li>6li>
<li>7li>
<li>8li>
<li>9li>
ul>
body>
<style>
body{
display: flex;
justify-content: center;
}
ul, li {
padding:0;
margin: 0;
}
li{
width: 250px;
height:200px;
list-style: none;
display: flex;
justify-content: center;
align-items: center;
}
li:nth-child(2n){
background:whitesmoke;
}
li:nth-child(2n+1){
background:yellow;
}
style>
<script>
// 首尾节流,计时器+时间戳
function throttle(fn, delay){
let timer = null
let startTime = 0
return function(...args){
let curTime = Date.now();
let remaining = delay - (curTime - startTime)
// 清除旧的计时器
clearTimeout(timer)
if(remaining <= 0 ){
fn.apply(this, args)
startTime = Date.now()
}else{
timer = setTimeout(()=>{
fn.apply(this, args)
startTime = Date.now()
}, remaining)
}
}
}
function handle(){
console.log(new Date())
}
const throttleHandler = throttle(handle, 500)
console.log('tt', throttleHandler)
window.addEventListener('scroll', throttleHandler)
script>
html>
在这里我们缩短节流时间,方便看效果。
可以看到每次滑动都至少触发两次事件,即首尾触发
虽然防抖和节流都是避免同一时间频繁执行处理函数,但是原理却有一些差别
::: note
应用场景
防抖 debounce
节流 throttle
:::
文章详细信息,请查看个人博客