文章目录
- 手写前端常用技巧-防抖节流
- 防抖
- 节流
- 1. 首节流
- 2. 尾节流
- 3. 首尾节流
- 总结
手写前端常用技巧-防抖节流
防抖:当持续触发事件时,一定时间内没有再触发事件,才会在一段时间之后触发事件处理函数。
节流:当持续触发事件时,保证一段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 = nullreturn function(...args){if(time){clearTimeout(time)}time = setTimeout(()=>{fn.apply(this, args)},delay)}}function onInput(e){val = e.target.valueif(val){console.log('有防抖',val)}}const debounceInput = debounce(onInput, 300)function onInput1(e){val = e.target.valueif(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 = nowfn.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 = nullreturn 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 = nulllet startTime = 0return 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来判断
:::
文章详细信息,请查看个人博客















