工作生活

函数防抖(闭包作用域)

2019-07-03  本文已影响0人  chenjieyi

今天,小洁和小惠看了(实现)函数防抖的代码,本来是要解决防抖,我们却困惑为什么连续点击三次会执行三次定时器(希望不会有人像我们一样傻有这种困惑),下面是待解决的问题(看动图)及代码
(为了下面的一系列描述可以简单粗暴,我把网友的代码改编了一下)
代码(此处还没实现函数防抖)如下:

// Js
var count = 0;
// 防抖的重点在于闭包作用域和清除定时器
function debounce() {
    consoleTime("1.debounce")

    var timer; // 定时器
    clearTimeout(timer); // 清除定时器
    timer = setTimeout(function () {
        funct();
    }, 1000);
}

// 定时器要执行的函数
function funct(args) {
    consoleTime("2.定时器")
    console.log("----- 分割线 -----")

    let testId = document.getElementById("test");
    ++count;
    testId.innerHTML = `hello ${count}`;
}

// 打印时间
function consoleTime(text) {
    let date = new Date();
    console.log(text, date.toLocaleTimeString(), date.getMilliseconds());
}

// html
<button onclick="debounce()">点击</button>
待解决防抖问题.gif

敲黑板,下面进入重点了,在上述代码基础上实现函数防抖,代码如下。

业务场景:假设客户在保存表单时,然后不小心连续点击了两次保存,那么就会发送两次请求。
那么我们为了解决这个不小心连续点击发送多次请求的问题,设定1秒内不管我们点多少次,都只发送一次请求。而函数防抖就是,不管你在设定的时间内点击了多少次,只有在最后一次才执行了你的目标函数。

var count = 0;
// 防抖的重点在于闭包作用域和清除定时器
function debounce() {
    var timer; // 定时器
    // 重点
    return function () {
        consoleTime("1.闭包")

        clearTimeout(timer); // 清除定时器,重点
        timer = setTimeout(function () {
            funct();
        }, 1000);
    }
}
// 定时器要执行的函数
function funct(args) {
    consoleTime("2.定时器")
    console.log("----- 分割线 -----")

    let testId = document.getElementById("test");
    ++count;
    testId.innerHTML = `hello ${count}`;
}

// 打印时间
function consoleTime(text) {
    let date = new Date();
    console.log(text, date.toLocaleTimeString(), date.getMilliseconds());
}

// 重点:先把debounce函数返回的匿名函数(闭包)赋值给一个变量
var test = debounce()

// html, 这里看清楚了,onclick绑定的是test不是debounce
<button onclick="test()">点击</button>
实现函数防抖的点击.gif

分析:
两个知识点(闭包作用域和定时器)
1、var test = debounce()
2、return function(){...}
3、clearTimeout(timer);

实现原理:
1、需要设定在某个时间内,只执行最后一次,因此用到了定时器setTimeout 来设定时间。

2、因为只执行最后一次,所以需要在每次执行之前把上一次的清除掉,因为设定时间还没到,那么定时器里的函数还没执行,所以我们清除了上一次的定时器函数就不会执行了。因此有重点3,所以每次我们都把定时器setTimeout返回的id记录下来。

3、使用闭包,是为了在它所在的作用域保存setTimeout返回的id,以便于在设定时间内点击时清除上一次的setTimeout。

4、如果onclick绑定debounce返回的匿名函数,每一次点击,debounce都会重新执行。那么clearTimeout是清除不了上一次定时器的。

5、onclick绑定test,每次点击,test()都能访问debounce()的内部作用域,所以能记录每次定时器setTimeout返回的id,并清除上一次的定时器。(闭包所在的内部作用域变量不会被回收)

本来没打算写函数防抖的,因为网上很多文章,我写这个是为了记录学习理解的内容。写着写着不会表达了,如有错误表达望指出。

上一篇 下一篇

猜你喜欢

热点阅读