JS实现节流和防抖之防抖(一)

前言


在前端开发中经常会遇到一些频繁触发的事件:

1. scorll、focus
2. mousedown、mousemove
3. keydown、keyup
4. 恶意频繁点击
...

为此,我们举个示例代码来了解事件如何频繁的触发:

我们写个index.html文件:




    

代码效果如下:随着鼠标的移动count不断增加

因为这个例子很简单,所以浏览器完全反应的过来,可是如果是复杂的回调函数或是 ajax 请求呢?假设 1 秒触发了 50 次,每个回调就必须在 1000 / 50 = 20ms 内完成,否则就会有卡顿出现。

为了解决这个问题,一般有两种解决方案:

  1. debounce 防抖
  2. throttle 节流

防抖


防抖的原理
触发事件时,只在事件触发 n 秒后才执行,如果你在一个事件触发的 n 秒内又触发了这个事件,那我就以新的事件的时间为准,n 秒后才执行。比如频繁触发的某一函数,防抖可以只让最后一次执行。总之,就是要等你触发完事件的 n 秒内不再触发事件,我才执行,真是任性呐!

深入理解:让函数执行者冷静下来后(不一直抖动后),才真正执行。
 

在使用了 debounce 后,在鼠标停止移动的1秒后执行了一次操作。

虽然我们实现了函数的基本原理,但是你会发现存在一些问题

1.this指向


...
    function getUserAction(e) {
        console.log(this)
        container.innerHTML = count++;
    };
...

在不使用 debounce 前,我们如果在 getUserAction 打印this,指向的是 id 为 container 的元素。
image.png
所以我们需要将 this 指向正确的对象。

我们修改下代码:

// 第二版
function debounce(func, wait) {
    var timer;
    return function () {
        var context = this;
        clearTimeout(timer)
        timer = setTimeout(function(){
            func.apply(context) // 修复this指向问题
        }, wait);
    }
}

现在 this 已经可以正确指向了。

2.event对象


...
    function getUserAction(e) {
        console.log(e)
        container.innerHTML = count++;
    };
...

在不使用 debounce 前,我们如果在 getUserAction 打印e,指向的是 mouseevent 这个事件。
image.png
所以我们需要将 e 指向正确的事件

// 第三版
function debounce(func, wait) {
    var timer;
    return function () {
        var context = this;
        var e = arguments;
        clearTimeout(timer)
        timer = setTimeout(function(){
            func.apply(context,e) // 修复 this、e 指向问题
        }, wait);
    }
}

你可能感兴趣的:(javascript,html)