JS函数节流和函数防抖

栏目: JavaScript · 发布时间: 6年前

内容简介:防抖(如果一个事件被频繁触发多次,并且触发的时间间隔过短,则防抖函数可以使得对应的事件处理函数只执行最后触发的一次。 函数防抖可以把多个顺序的调用合并成一次。如果一个事件被频繁触发多次,节流函数可以按照固定频率去执行对应的事件处理方法。 函数节流保证一个事件一定时间内只执行一次。
  • 在浏览器中某些计算和处理要比其他的昂贵很多。例如 DOM 操作比起非 DOM 交互需要更多的内存和CPU占用时间。连续尝试进行过多的 DOM 操作可能会导致浏览器挂起,甚至崩溃;
  • 例如当调整浏览器大小的时候, resize 事件会连续触发;如果在 resize 事件处理程序内部尝试进行 DOM 操作,其高频率的更改可能会让浏览器崩溃;
  • 为了绕开上面的问题,需要对该类函数进行节流;

2.什么是函数防抖和函数节流

防抖( debounce )和节流( throttle )都是用来控制某个函数在一定时间内执行多少次的技巧,两者相似而又不同。 背后的基本思想是 某些代码不可以在没有间断的情况下连续重复执行。

2.1 函数防抖 ( debounce )

如果一个事件被频繁触发多次,并且触发的时间间隔过短,则防抖函数可以使得对应的事件处理函数只执行最后触发的一次。 函数防抖可以把多个顺序的调用合并成一次。

2.2 函数节流 ( throttle )

如果一个事件被频繁触发多次,节流函数可以按照固定频率去执行对应的事件处理方法。 函数节流保证一个事件一定时间内只执行一次。

3.应用场景

类型 场景
函数防抖 1. 手机号、邮箱输入检测
2. 搜索框搜索输入(只需最后一次输入完后,再放松Ajax请求)
3. 窗口大小 resize (只需窗口调整完成后,计算窗口大小,防止重复渲染)
4.滚动事件 scroll (只需执行触发的最后一次滚动事件的处理程序)
5. 文本输入的验证(连续输入文字后发送 AJAX 请求进行验证,(停止输入后)验证一次就好
函数节流 1. DOM 元素的拖拽功能实现( mousemove
2. 射击游戏的 mousedown / keydown 事件(单位时间只能发射一颗子弹)
3. 计算鼠标移动的距离( mousemove
4. 搜索联想( keyup
5. 滚动事件 scroll ,(只要页面滚动就会间隔一段时间判断一次)

4.如何实现

4.1 函数防抖实现

function debounce(fn, delay, scope) {
    let timer = null;
    // 返回函数对debounce作用域形成闭包
    return function () {
        // setTimeout()中用到函数环境总是window,故需要当前环境的副本;
        let context = scope || this, args = arguments;
        // 如果事件被触发,清除timer并重新开始计时
        clearTimeout(timer);
        timer = setTimeout(function () {
            fn.apply(context, args);
        }, delay);
    }
}
复制代码
  • 代码解读
  1. 第一次调用函数,创建一个定时器,在指定的时间间隔之后运行代码;
  2. 当第二次调用该函数时,它会清除前一次的定时器并设置另一个;
  3. 如果前一个定时器已经执行过了,这个操作就没有任何意义;
  4. 然而,如果前一个定时器尚未执行,其实就是将其替换为一个新的定时器;
  5. 目的是 只有在执行函数的请求停止了 delay 时间之后才执行

4.2 函数节流实现

4.2.1 利用时间戳简单实现

function throttle(fn, threshold, scope) {
    let timer;
    let prev = Date.now();
    return function () {
        let context = scope || this, args = arguments;
        let now = Date.now();
        if (now - prev > threshold) {
            prev = now;
            fn.apply(context, args);
        }
    }
}
复制代码

4.2.2 利用定时器简单实现

function throttle2(fn, threshold, scope) {
    let timer;
    return function () {
        let context = scope || this, args = arguments;
        if (!timer) {
            timer = setTimeout(function () {
                fn.apply(context, args);
            }, threshold);
        }
    }
}
复制代码

5 举例( scroll 事件)

CSS代码

.wrap {
       width: 200px;
        height: 330px;
        margin: 50px;
        margin-top: 200px;
        position: relative;
        float: left;
        background-color: yellow;
    }
    .header{
        width: 100%;
        height: 30px;
        background-color: #a8d4f4;
        text-align: center;
        line-height: 30px;
    }
    .container {
        background-color: pink;
        box-sizing: content-box;
        width: 200px;
        height: 300px;
        overflow: scroll;
        position: relative;
    }
    .content {
        width: 140px;
        height: 800px;
        margin: auto;
        background-color: #14ffb2;
    }
复制代码

HTML代码

<div class="wrap">
        <div class="header">滚动事件:普通</div>
        <div class="container">
            <div class="content"></div>
        </div>
    </div>
    <div class="wrap">
        <div class="header">滚动事件:<strong>加了函数防抖</strong></div>
        <div class="container">
            <div class="content"></div>
        </div>
    </div>
    <div class="wrap">
        <div class="header">滚动事件:<strong>加了函数节流</strong></div>
        <div class="container">
            <div class="content"></div>
        </div>
    </div>
复制代码

JS代码

let els = document.getElementsByClassName('container');
    let count1 = 0,count2 = 0,count3 = 0;
    const THRESHOLD = 200;

    els[0].addEventListener('scroll', function handle() {
        console.log('普通滚动事件!count1=', ++count1);
    });
    els[1].addEventListener('scroll', debounce(function handle() {
        console.log('执行滚动事件!(函数防抖) count2=', ++count2);
    }, THRESHOLD));
    els[2].addEventListener('scroll', throttle(function handle() {
        console.log(Date.now(),', 执行滚动事件!(函数节流) count3=', ++count3);
    }, THRESHOLD));
复制代码
// 函数防抖
function debounce(fn, delay, scope) {
    let timer = null;
    let count = 1;
    return function () {
        let context = scope || this,
            args = arguments;
        clearTimeout(timer);
        console.log(Date.now(), ", 触发第", count++, "次滚动事件!");
        timer = setTimeout(function () {
            fn.apply(context, args);
            console.log(Date.now(), ", 可见只有当高频事件停止,最后一次事件触发的超时调用才能在delay时间后执行!");
        }, delay);
    }
}
复制代码
// 函数节流
function throttle(fn, threshold, scope) {
    let timer;
    let prev = Date.now();
    return function () {
        let context = scope || this, args = arguments;
        let now = Date.now();
        if (now - prev > threshold) {
            prev = now;
            fn.apply(context, args);
        }
    }
}
复制代码

以上所述就是小编给大家介绍的《JS函数节流和函数防抖》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Web Analytics 2.0

Web Analytics 2.0

Avinash Kaushik / Sybex / 2009-10-26 / USD 39.99

The bestselling book Web Analytics: An Hour A Day was the first book in the analytics space to move beyond clickstream analysis. Web Analytics 2.0 will significantly evolve the approaches from the fir......一起来看看 《Web Analytics 2.0》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

MD5 加密
MD5 加密

MD5 加密工具