为了账号安全,请及时绑定邮箱和手机立即绑定

JS函数的防抖和节流(一)

标签:
Html5

什么是防抖和节流

防抖:动作绑定事件,动作发生后在设置的一定时间后触发,如果在这个时间内,再次发生该动作,就要重新再等待一定时间再触发事件(事件隔一定时间时候还会触发)

节流:在动作绑定事件之后,动作发生后一段时间后触发事件,在这个时间内,如果再次触发这个动作,则会被无视,等到事件执行完毕再重新触发

为什么会用到防抖或者节流呢?

在实际中使用的window 的 resize、scroll,mousedown、mousemove,keyup、keydown,这些事件我们都会常用到

var count = 1;var container = document.getElementById('container');function getUserAction() {
    container.innerHTML = count++;};container.onmousemove = getUserAction;

上面的js方法,是鼠标移入之后在container容器上输出数字,且数字随着鼠标移动自动加一,在这个简单的函数中我们看到数字会变化很快,但是如果是复杂的请求呢。特别是在业务复杂时,在实际项目中,考虑到入参数据的处理及网络,假设 1 秒触发了 60 次请求,每个回调就必须在 1000 / 60 = 16.67ms 内完成,否则就会有卡顿出现,这样就很容易卡顿。

防抖的实现方式

//第一个实现方式function debounce(func, time) {
    let timeout;
    return function () {
        clearTimeout(timeout)
        timeout = setTimeout(func, time);
    }}

使用例子一

container.onmousemove = debounce(getUserAction, 1000);
//这样在鼠标移入之后不管怎么移动,在1s内是不会再次触发这个函数的

如果我们在getUserAction函数中console.log(this),在不使用debounce函数的时候,this的值为容器,如果使用this则指向了debounce。

//第二个实现方式,改变this的指向function debounce(func, wait) {
    var timeout;

    return function () {
        var _this= this;

        clearTimeout(timeout)
        timeout = setTimeout(function(){
            func.apply(_this)
        }, wait);
    }}//这样this会指向容器

JavaScript 在事件处理函数中会提供事件对象 event,如果我们在getUserAction函数中打印event,可以打印出event,如果在上面的debounce函数中打印,只会打印出undefined。所以我们可以做如下修改:

// 第三次修改function debounce(func, wait) {
    var timeout;

    return function () {
        var context = this;
        var args = arguments;

        clearTimeout(timeout)
        timeout = setTimeout(function(){
            func.apply(context, args)
        }, wait);
    }}// 在这个方法中用到apply,解决了event输出undefined。

在上面的三个方法修改中,我们发现只会在操作之后到一定时间之后才执行,如果我们有这样一个需求:我们希望方法立即执行,然后到n秒之后再去重新触发执行,我们就可以增加一个immediate参数去判断,如果为true则立即执行(核心方法已经在上面了,后面的扩展时根据实际需求,对方法进行改造)

//对方法进行扩展function debounce(func, wait, immediate) {

    var timeout;

    return function () {
        var context = this;
        var args = arguments;

        if (timeout) clearTimeout(timeout);
         // 如果需要立即执行,则执行下面方法        if (immediate) {
            // 如果已经执行过,不再执行,没有执行则立即执行            var callNow = !timeout;
            timeout = setTimeout(function(){
                timeout = null;
            }, wait)
            if (callNow) func.apply(context, args)
        }
        else {
            timeout = setTimeout(function(){
                func.apply(context, args)
            }, wait);
        }
    }}

如果getUserAction是个有返回值的函数怎么办呢?但是当 immediate 为 false 的时候,因为使用了 setTimeout ,我们将 func.apply(context, args) 的返回值赋给变量,最后再 return 的时候,值将会一直是 undefined,所以我们只在 immediate 为 true 的时候返回函数的执行结果。

//再次修改function debounce(func, wait, immediate) {

    var timeout, result;

    return function () {
        var context = this;
        var args = arguments;

        if (timeout) clearTimeout(timeout);
        if (immediate) {
            // 如果已经执行过,不再执行            var callNow = !timeout;
            timeout = setTimeout(function(){
                timeout = null;
            }, wait)
            if (callNow) result = func.apply(context, args)
        }
        else {
            timeout = setTimeout(function(){
                func.apply(context, args)
            }, wait);
        }
        return result;
    }}//这个方法与上面的区别就是把返回值return出去。

PS: 以前在工作中遇到一些问题或者解决一些问题的时候,没把问题总结归纳,然后现在想开始把所有问题系统的归纳总结一下,从这篇开始会尽量每周写一篇,把知识点总结一下,不仅限于前端部分。


点击查看更多内容
2人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消