函数防抖:函数被触发后过一段时间再执行,如果在这段时间内又被触发,则重新计时,即将多次高频操作优化为只在最后一次执行。应用场景为用户连续输入,只需要在输入结束后做一次校验即可,比如input搜索或校验。简而言之,就是在input请求时使用防抖。
function debounce(func, ms = 1000) { let timer; return function (...args) { if (timer) { clearTimeout(timer) } timer = setTimeout(() => { func.apply(this, args) }, ms) } } // 测试
const task = () => { console.log('run task') } const debounceTask = debounce(task, 1000) window.addEventListener('scroll', debounceTask)
函数节流:函数在一段时间内只能被触发一次,如果这段时间内被触发多次,则只有一次生效,即每隔一段时间执行一次,也就是降低频率,将高频操作优化成低频操作。应用场景为滚动条事件或窗口resize事件,通常每隔100-500ms执行一次。简而言之,就是在滚动条请求时使用节流。
function throttle(func, ms = 1000) { let canRun = true
return function (...args) { if (!canRun) return canRun = false setTimeout(() => { func.apply(this, args) canRun = true }, ms) } } // 测试
const task = () => { console.log('run task') } const throttleTask = throttle(task, 1000) window.addEventListener('scroll', throttleTask)
防抖或节流一般使用:
import debounce from 'lodash/debounce' debounce(()=>search(value), 500)
在类组件中使用防抖或节流:
import React from 'react'; import ReactDOM from 'react-dom'; import 'antd/dist/antd.css'; import { Input } from 'antd'; import throttle from 'lodash/debounce'; class Search extends React.Component { constructor(props) { super(props) this.handleSearch = throttle(this.handleOnChange, 200); } handleOnChange = (e) => { console.log(e.target.value) } render() { return ( <Input onChange={this.handleSearch} />
) } } ReactDOM.render( <Search />,
document.getElementById('container'), );
在函数组件中使用防抖或节流,需要使用useCallback或useRef缓存变量和方法:
import React, { useCallback } from 'react'; import ReactDOM from 'react-dom'; import 'antd/dist/antd.css'; import { Input } from 'antd'; import debounce from 'lodash/debounce'; import throttle from 'lodash/throttle'; const Search = () => { const handleOnChange = (e) => { console.log(e.target.value) } const handleSearch = useCallback(throttle((e) => handleOnChange(e), 500), []) return (<Input onChange={handleSearch} placeholder="Basic usage" />)
} ReactDOM.render(<Search />, document.getElementById('container'));
或
import React, { useRef } from 'react'; import ReactDOM from 'react-dom'; import 'antd/dist/antd.css'; import { Input } from 'antd'; import debounce from 'lodash/debounce'; import throttle from 'lodash/throttle'; const Search = () => { const handleOnChange = (e) => { console.log(e.target.value) } const handleSearch = useRef(throttle((e) => handleOnChange(e), 500)).current return (<Input onChange={handleSearch} placeholder="Basic usage" />)
} ReactDOM.render(<Search />, document.getElementById('container'));
在函数组件里使用debounce,不使用lodash:
import { useEffect } from 'react'
function useDebounce(fn, delay, dep=[]) { useEffect(()=>{ let timer; timer = setTimeout(fn, delay); return ()=>clearTimeout(timer); }, [...dep] ) } export default useDebounce // 调用
useDebounce(()=>search(value), 500, [value])
或
import { useRef } from 'react'
function useDebounce(fn, delay) { const timer = useRef(null); return () => { clearTimeout(timer.current); timer.current = setTimeout(fn, delay); } } export default useDebounce // 调用
const debounceSearch = useDebounce(() => handleParams(params), 500) useEffect(()=>{debounceSearch()},[value]