mis-lab / Front-End-Question-Discussion

前端基础问题 每日一题
1 stars 0 forks source link

函数防抖 、节流的原理 / 区别 #25

Open Reaper622 opened 4 years ago

Reaper622 commented 4 years ago

函数防抖

触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间。

原理: 在每次触发事件时都取消之前的延时调用方法。


function debounce(fn) {
let timeout = null; // 创建一个用来存储定时器的变量 「此处用到了闭包」
return function () {
clearTimeout(timeout); // 清除之前的定时器
// 产生一个新的定时器,这样保证在点击按钮后的2000ms内如果还有点击事件的话,不会触发fn
timeout = setTimeout(() => {
fn.apply(this, arguments)
}, 2000)
};
}

function Hello() { console.log('hello 防抖成功') }

const button = document.getElementById('button'); button.addEventListener('click', debounce(Hello))

此时,不论点击按钮多少次,它都只会在不点两秒后执行一次方法。
防抖一般用于交互事件,例如点击事件,它的核心是在一定时间段内的函数调用,只让他执行一次。有时我们同样通过设置点击后特定时间内按钮为`disabled`状态来达到防抖目的。

## 函数节流
触发高频时间后n秒内函数只执行这一次,其他触发直接不执行,所以函数节流会稀释函数的执行频率。
> 原理:每次触发事件都判断是否有等待执行的延时函数,如果此时有,则直接不再执行当前新触发的函数,而是等待原来的延时函数执行。
```javascript
function throttle(fn) {
    let canRun = true; // 记录一个值用来判断是否当前是否处在一个执行循环内
    return function () {
        if (!canRun) return ; // 如果正在一个执行内 那么直接退出不执行函数
        canRun = false; // 如果进入执行环境 则设置为false
        // 将外部函数传入setTimeout
        setTimeout(() => {
            fn.apply(this, arguments);
            // 如果执行完毕 则设置标记为 true 表示可以执行下一次循环
            canRun = true;
        }, 1000)
    }
}
function Point(e) {
    console.log(e.clientX, e.clientY);
}
const area = document.getElementById('area');
area.addEventListener('click', throttle(Point));

此时无论在1秒内点击多少次 还是1s只会执行一次。 节流一般适用于DOM变化操作,例如: onkeypressonscrollresize等情况,如果在这些事件触发时执行代码,会一直进行重复执行,此时应该减少一段时间内的执行次数来节省性能。

节流类比于水龙头,如果我们一直把水龙头开的很大,它就会一直源源不断地流出,此时我们可以拧紧水龙头,让流水的频率降低,从而达到节省资源的目的。

总结

防抖: 特定的时间段内,只让他执行一次,每次执行都会产生新的定时。 节流:在一个函数正在执行的时间段内的其他函数被忽略,只有在执行完毕后才会进行下一次执行。