防抖和节流

179 阅读3分钟

「这是我参与2022首次更文挑战的第18天,活动详情查看:2022首次更文挑战

防抖

背景

我们在平时开发的时候,会有很多场景会频繁触发事件,比如说input框的input事件,搜索框实时发请求,resize,onscroll,onmousemove等等,有些时候,我们并不能或者不想频繁触发事件,那怎么办呢?这时候就应该用到函数防抖和函数节流了。

定义

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

生活中的例子:如果有人进电梯(触发事件),那电梯将在10秒后出发(执行事件监听器),这时如果又有人进电梯了(在10秒内再次触发该事件),我们又得等10秒再出发(重新计时)。

本质:防抖动是将多次执行变为最后一次执行

用法和使用场景

思路:每次触发事件时都取消之前的延时调用方法

可以应用在输入框搜索,控制调用接口的频率。也可以用来监听窗口的变化。

function debounce(fn) {
    let timeout = null; // 创建一个标记用来存放定时器的返回值
    return function() {
        // 每当用户输入的时候把前一个setTimeout clear掉
        clearTimeout(timeout);
        // 然后又创建一个新的setTimeout,
        // 这样就能保证输入字符后的 interval 间隔内如果还有字符输入的话,就不会执行fn函数
        timeout = setTimeout(() => {
            // 关键在第一个参数,为了确保上下文环境为当前的this,所以不能直接用fn
            fn.apply(this, arguments);
        }, 500);
    }
}
function sayHi() {
    console.log('防抖成功');
}
var inp = document.getElementById('inp');
inp.addEventListener('input', debounce(sayHi)); // 防抖

二、节流

背景

我们在平时开发的时候,会有很多场景会频繁触发事件,比如说input框的input事件,搜索框实时发请求,resize,onscroll,onmousemove等等,有些时候,我们并不能或者不想频繁触发事件,那怎么办呢?这时候就应该用到函数防抖和函数节流了。

定义

 高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率。

本质:节流是将多次执行变为每隔一段时间执行

用法和使用场景

思路:每次触发事件时都判断当前是否有等待执行的延时函数 可以应用在监听滚动条的位置,或者频繁点击按钮的优化。

function throttle(fn) {
    let canRun = true; // 通过闭包保存一个标记
    return function() {
        if (!canRun) return; // 在函数开头判断标记是否为true,不为true,则return
        canRun = false;
        setTimeout(() => {
            fn.apply(this, arguments); //关键在第一个参数,为了确保上下文环境为当前的this,所以不能直接用fn。
            // 最后在setTimeout执行完毕后再把标记设置为true
            // (关键)表示可以执行下一次循环了。
            // 当定时器没有执行的时候标记永远是false,在开头被return掉
            canRun = true;
        }, 500)
    }
}
function sayHi(e) {
    console.log(e.target.innerWith, e.target.innerHeight);
}
window.addEventListener('resize', throttle(sayHi)); // 节流

三、防抖和节流的区别

防抖:动作绑定事件,动作发生后一定时间后触发事件,在这段时间内,如果该动作又发生,则重新等待一 定时间再触发事件。

节流:动作绑定事件,动作发生后一段时间后触发事件,在这段时间内,如果动作又发生,则无视该动作,直到事件执行完后,才能重新触发。

// 防抖的实现
function debounce(func, time) {
    let timer = null;
    return () => {
        clearTimeout(timer);
        timer = setTimeout(() => {
            func.apply(this, arguments);
        }, time);
    }
}
// 节流的实现
function throtte(func, time) {
    let activeTime = 0;
    return () => {
        const current = Date.now();
        if (current - activeTime > time) {
            func.apply(this, arguments);
            activeTime = Date.now();
        }
    }
}

JQuery的ready函数与JS的onload的区别:

1)执行时间:

window.onload必须等到页面内包括图片的所有元素加载完毕后才能执行;

$(document).ready()是Dom结构绘制完毕后就执行,不必等到加载完毕。

2)编写个数不同:

window.onload不能同时编写多个,如果有多个window.onload方法,只会执行一个;

$(document).ready()可以同时编写多个,并且都可以得到执行。