JavaScript中的防抖与节流、在react class及hook中使用防抖与节流
函数防抖:函数被触发后过一段时间再执行,如果在这段时间内又被触发,则重新计时,即将多次高频操作优化为只在最后一次执行。应用场景为用户连续输入,只需要在输入结束后做一次校验即可,比如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]