1. 防抖 (debounce)
- 当事件触发时,相应的函数并不会立即触发,而是会等待一定的时间;
- 当事件密集触发时,函数的触发会被频繁的推迟;
- 只有等待了一段时间也没有事件触发,才会真正的执行响应函数;
应用场景
例如: 输入框中频繁的输入内容 频繁的点击按钮,触发某个事件 监听浏览器滚动事件,完成某些特定操作 用户缩放浏览器的resize事件等等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| function debounce(fn, delay, immediate = false) { let timer = null let isInvoke = false
const _debounce = function(...args) { return new Promise((resolve, reject) => { if (timer) clearTimeout(timer)
if (immediate && !isInvoke) { const result = fn.apply(this, args) resolve(result) isInvoke = true } else { timer = setTimeout(() => { const result = fn.apply(this, args) resolve(result) isInvoke = false timer = null }, delay) } }) }
_debounce.cancel = function() { if (timer) clearTimeout(timer) timer = null isInvoke = false }
return _debounce }
|
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <input type="text"> <button id="cancel">取消</button>
<script src="debounce.js"></script> <script> const inputEl = document.querySelector("input") let counter = 0
const inputChange = function(event) { console.log(`触发第${++counter}次`, this, event) return "aaaaaaaaaaaa" }
const debounceChange = debounce(inputChange, 3000, false) inputEl.oninput = (...args) => { debounceChange.apply(inputEl, args).then(res => { console.log("Promise的返回值结果:", res) }) }
const cancelBtn = document.querySelector("#cancel") cancelBtn.onclick = function() { debounceChange.cancel() } </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| import { Input, Space } from 'antd'; import { debounce } from '@/util'; import { useEffect, useState } from 'react';
export default () => { const [text, setText] = useState('');
useEffect(() => { const delayed = debounce(() => { console.log(text); }, 1000); delayed(); return delayed.cancel; }, [text]);
return ( <Space direction="vertical"> <Input value={text} onChange={(e) => { setText(e.target.value); }} /> </Space> ); };
|
节流 (throttle)
- 如果这个事件会被频繁触发,那么节流函数会按照一定的频率来执行函数;
- 不管在这个中间有多少次触发这个事件,执行函数的频率总是固定的;
应用场景
例如: 鼠标移动事件 王者荣耀攻击键, 点击再快也是以一定攻速(频率)进行攻击等等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| function throttle(fn, interval, options = { leading: true, trailing: false }) { const { leading, trailing, resultCallback } = options let lastTime = 0 let timer = null
const _throttle = function(...args) { return new Promise((resolve, reject) => { const nowTime = new Date().getTime() if (!lastTime && !leading) lastTime = nowTime
const remainTime = interval - (nowTime - lastTime) if (remainTime <= 0) { if (timer) { clearTimeout(timer) timer = null }
const result = fn.apply(this, args) resolve(result) lastTime = nowTime return }
if (trailing && !timer) { timer = setTimeout(() => { timer = null lastTime = !leading ? 0: new Date().getTime() const result = fn.apply(this, args) resolve(result) }, remainTime) } }) }
_throttle.cancel = function() { if(timer) clearTimeout(timer) timer = null lastTime = 0 }
return _throttle }
|
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <input type="text"> <button id="cancel">取消</button>
<script src="throttle.js"></script> <script> const inputEl = document.querySelector("input") let counter = 0 const inputChange = function(event) { console.log(`触发第${++counter}次`, this, event) return 11111111111 }
const _throttle = throttle(inputChange, 3000, { leading: false, trailing: true, }) inputEl.oninput = (...args) => { _throttle.apply(inputEl, args).then(res => { console.log("Promise的返回值结果:", res) }) }
const cancelBtn = document.querySelector("#cancel") cancelBtn.onclick = function() { _throttle.cancel() } </script>
|