手写前端常用技巧-防抖节流
防抖
- 源代码
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
- 结果分析
- 没有防抖的输入框持续输入时,每键入一个字母都执行一次处理函数
- 有防抖的输入框持续输入时,在键入字母结束之后才执行一次处理函数
:::
节流
1. 首节流
首节流,时间戳的实现,首次触发立即执行,停止触发后,没办法再次执行
- 源代码
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>节流throttle
title>
head> <body> <ul> <li>1
li> <li>2
li> <li>3
li> <li>4
li> <li>5
li> <li>6
li> <li>7
li> <li>8
li> <li>9
li> <li>1
li> <li>2
li> <li>3
li> <li>4
li> <li>5
li> <li>6
li> <li>7
li> <li>8
li> <li>9
li>
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>

可以看到,只要滑动了,就会触发事件,但是停止滑动之后,不会触发最后一次。
2. 尾节流
定时器实现,不会立即执行,而是在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>节流throttle
title>
head> <body> <ul> <li>1
li> <li>2
li> <li>3
li> <li>4
li> <li>5
li> <li>6
li> <li>7
li> <li>8
li> <li>9
li> <li>1
li> <li>2
li> <li>3
li> <li>4
li> <li>5
li> <li>6
li> <li>7
li> <li>8
li> <li>9
li>
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>

可以看到我们停止滑动之后还是触发了事件
3. 首尾节流
- 源代码
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>节流throttle
title>
head> <body> <ul> <li>1
li> <li>2
li> <li>3
li> <li>4
li> <li>5
li> <li>6
li> <li>7
li> <li>8
li> <li>9
li> <li>1
li> <li>2
li> <li>3
li> <li>4
li> <li>5
li> <li>6
li> <li>7
li> <li>8
li> <li>9
li>
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- search搜索联想,用户在不断输入值时,用防抖来节约请求资源。
- window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次
- 节流
throttle- 鼠标不断点击触发,mousedown(单位时间内只触发一次)
- 监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断
:::
文章详细信息,请查看个人博客
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/222685.html原文链接:https://javaforall.net
