javascript中的防抖和节流(面试高频考点)

什么是防抖和节流,如何实现?
javascript 中的函数大多数情况下都是由用户主动调用触发的,除非是函数本身的实现不合理,否则一般不会遇到跟性能相关的问题。但是在一些少数情况下,函数的触发不是由用户直接控制的。在这些场景下,函数有可能被非常频繁地调用,而造成大的性能问题。解决性能问题的处理方法 函数防抖 和 函数节流。
列举几个函数被频繁调用的场景:

  1. mousemove 事件:如果是实现一个拖拽功能,需要一直监听 mousemove 事件,在回调中获取元素当前位置,然后重置 DOM
    的位置来进行样式改变。如果不加以控制,每移动一定像素而触发的回调数量非常惊人,回调中又伴随这DOM操作,继而引发浏览器的重排和重绘,性能差的浏览器可能会直接假死。
  2. window.onresize 事件:为 window 对象绑定来 resize
    事件,当浏览器窗口大小被拖动而改变的时候,这个事件触发的频率非常之高,浏览器可能会出现和上述一样的情况。
  3. 射击游戏的mousedown/keydowm事件 (单位时间只能发射一颗子弹)
  4. 搜索联想,在搜索框搜索时,不是每个字符都去搜索一次,这样会频繁的调用函数
  5. 监听滚动事件判断是否到页面底部自动加载更多(scroll 事件)

– 对于上述的这些情况的解决方案就是函数防抖 (debounce)函数节流(throttle) , 其核心就是限制某一个方法的频繁触发。
函数防抖:
函数防抖,是防止函数在极短时间内的反复使用,造成资源的浪费。函数防抖在执行目标方法时会等待一段时间,当又执行相同的函数时,若前一个定时任务未执行完,则清除前一个的定时任务,重新开始计时。
代码实现:

/** 下面这个做法会频繁的调用函数 */
const txt = document.getElementsByClassName('txt')[0];
txt.onkeyup = function (e) {
    console.log(e.target.value);
}


/**
 * 将上面的写法添加防抖函数
 * 封装防抖函数(debounce)
 * debounce:简单防抖函数的实现 
 * 返回的是一个 防抖函数
 */
let txt = document.getElementsByClassName('txt')[0]

function debounce(func, waitTime) {
    let timerID = null;
    return function (...args) {
        if (timerID) { // 如果有存在的计时器还没结束的,把这个计时器清楚
            clearTimeout(timerID);
        }
        timerID = setTimeout(function () {
            func(...args);
        }, waitTime)
    }
}
var debounceHandle = debounce(function (e) {
    console.log(e.target.value)
}, 500)
txt.onkeyup = function (e) {
    debounceHandle(e);
}

函数节流:
函数节流的目的,也是为了防止一个函数短时间内被频繁的触发。但和防抖的原理不同,函数节流的核心思想是让连续的函数执行,变为固定时间段间断的执行
( 也就是说防抖是可以连续执行函数的,但是每次执行函数呢会看上一次执行的计时器是否已经清除了,如果还在的话就清除计时器并重开一个计时器,让函数等待一段时间执行,而节流是限制住时间,限制函数在规定的时间内只能执行一次,不能连续的执行函数)
关于节流的实现:有 2 中主流的实现方式, 一种是使用时间戳,一种是设置定时器

  1. 使用时间戳:
    触发事件时,取出当前的时间戳,然后减去之前的时间戳(最一开始值设为0),如果大于设置的时间周期,就要执行函数,然后更新时间戳为当前 时间戳,如果小于就不执行
  2. 使用定时器的:
    触发事件时设置一个定时器,再触发事件的时候,如果定时器存在,就不执行,直到定时器执行,然后执行函数,清空定时器。
    代码实现:
/**
 * 节流函数:throttle
 * 实现方式一: 使用时间戳
 * throttle : 使用时间戳的节流函数的简单实现
 * func : 要执行的函数
 * timeGap : 固定的时间间隔
 */
const txt = document.getElementsByClassName('txt')[0];

function throttle(func, timeGap) {
    var pre = 0;  //上一次的时间,最开始时时间为 0
    return function (...args) {
        var now = new Date();   // 获取当前的时间戳
        if (now - pre > timeGap) {
            func(...args);
            pre = now;
        }
    }
}
var throttleHandle = throttle(function (e) {
    console.log(e.target.value)
}, 2000)
txt.onkeyup = function (e) {
    throttleHandle(e);
}

/**
 * 实现节流函数的方式二: 通过定时器来实现
 * throttle : 使用定时器的节流函数的简单实现
 */
const txt = document.getElementsByClassName('txt')[0];

function throttle(func, timeGap) {
    var timerID = null;
    return function (...args) {
        if (!timerID) {
            func(...args);
            timerID = setTimeout(function () {
                timerID = null;
            }, timeGap)
        }
    }
}
var throttleHandle = throttle(function (e) {
    console.log(e.target.value)
}, 2000)
txt.onkeyup = function (e) {
    throttleHandle(e);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值