资讯专栏INFORMATION COLUMN

underscore源码解读之debounce

Flink_China / 1960人阅读

摘要:直接来分析返回的匿名函数部分。我第一次调用事件函数是在,按照设定,之后才能调用第二次方法,在这秒内,任何调用都是不执行的。这个难点解决了,其他就都好说。恩,那这个的解读就结束了,有什么地方我没写清楚的话,请给我留言。

刚写完一篇debounce(防抖)函数的实现,我又看了下underscore.js的实现方法。算是趁热打铁,分析一下underscore里实现的套路。

先贴上源码:

_.debounce = function(func, wait, immediate) {
    var timeout, args, context, timestamp, result;

    var later = function() {
        var last = _.now() - timestamp;
        console.log(last)
        if (last < wait && last >= 0) {
            console.log(1)
            timeout = setTimeout(later, wait - last);
        } else {
            console.log(2)
            timeout = null;
            if (!immediate) {
                result = func.apply(context, args);
                if (!timeout) context = args = null;
            }
        }
    };

    return function() {
        context = this;
        args = arguments;
        timestamp = _.now();
        var callNow = immediate && !timeout;
        console.log(timeout)
        if (!timeout) timeout = setTimeout(later, wait);
        if (callNow) {
            result = func.apply(context, args);
            context = args = null;
        }

        return result;
    };
};

一看可能有点多,我简化一下,整体其实就两部分:

_.debounce = function( func, wait, immediate){

    // 函数的回调部分
    // 当immediate === false时
    // func真正的执行部分
    function later(){};
    
    return function(){
        // 在这里判断func是否立即执行
        // 是否有计时器的存在
    }
}

上一篇文章已经分析过this的指向和event的传递,这里就不多说了。直接来分析返回的匿名函数部分。

return function() {
        context = this;
        args = arguments;
        // 这里调用了underscore封装的调用时间戳的方法
        // 等同于
        // timestamp = Date.now()
        timestamp = _.now();
        var callNow = immediate && !timeout;
        console.log(timeout)
        if (!timeout) timeout = setTimeout(later, wait);
        if (callNow) {
            result = func.apply(context, args);
            context = args = null;
        }
    };

这里我要说的是timestamp,它存储的是动作发生时的时间戳,假设我这里调用debounce时传入的wait为10000,也就是10秒。我第一次调用事件函数是在10:00:00,按照设定,10:00:10之后才能调用第二次方法,在这10秒内,任何调用都是不执行的。

当我第一次执行事件时

timeout = undefined;
immediate先设置为false

所以

callNow === false

只有这句话是执行的

if (!timeout) timeout = setTimeout(later, wait);

那接着来看later都有什么:

var later = function() {
  //     var last = Date.now() - timestamp;
    var last = _.now() - timestamp;
    console.log(last)
    if (last < wait && last >= 0) {
        console.log(1)
        timeout = setTimeout(later, wait - last);
    } else {
        console.log(2)
        timeout = null;
        if (!immediate) {
            result = func.apply(context, args);
            if (!timeout) context = args = null;
        }
    }
};

在上一篇中,判断wait内重复输入,我们取消事件的方法是这样的

if(timer){clearTimeout(timer)}

但在这里,我们是不是都还没看到怎么处理wait时间内,重复输入无效的问题?别急,现在就来说。玄妙都在这个last变量上。

之前说过,timestamp存储的是第一次事件执行时的时间戳(10:00:00),但现在我没想等十秒,过了五秒我就触发了第二次事件。所以timestamp现在的内容就变成新的时间戳了(10:00:05)。但问题是,timer的回调函数至少要到10:00:10之后才会执行,也就是说

last>=5

由于代码执行堵塞导致last>10的情况有可能存在,但是不符合我们现在讨论的,而且真的是太特殊了,我们就不说了。那就假设last为5秒(5000ms)。

last < wait && last >= 0

这句话就是true,那就执行里面的代码。但注意看里面计时器对于时间的写法。

wait - last

换个说法就是,你在10:00:00启动了我,但是你在10:00:05又动了,我原本应该在10:00:10执行,但是现在惩罚你提前行动,那你之前等的时间就不算,你要再重新多等这几秒10:00:15。

这个难点解决了,其他就都好说。

lster剩余的部分就是判断如果当初设置的是立即执行(immediate = true),func就不再执行一遍了,否则(immediate = false)func执行。

恩,那这个的解读就结束了,有什么地方我没写清楚的话,请给我留言。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/92012.html

相关文章

  • 浅谈 Underscore.js 中 _.throttle 和 _.debounce 的差异

    摘要:如果想忽略结尾边界上的调用,传入返回客户调用函数上次执行时间点延迟执行函数若设定了开始边界不执行选项,上次执行时间始终为首次执行时,如果设定了开始边界不执行选项,将上次执行时间设定为当前时间。 文章转自:https://blog.coding.net/blog/...注: _.throttle 和 _.debounce是Underscore.js库的两个针对函数节流的方法,用于处理高频...

    alighters 评论0 收藏0
  • JavaScript 函数节流和函数去抖应用场景辨析

    摘要:函数节流和去抖的出现场景,一般都伴随着客户端的事件监听。函数节流的核心是,让一个函数不要执行得太频繁,减少一些过快的调用来节流。 概述 也是好久没更新 源码解读,看着房价蹭蹭暴涨,心里也是五味杂陈,对未来充满恐惧和迷茫 ...(敢问一句你们上岸了吗) 言归正传,今天要介绍的是 underscore 中两个重要的方法,函数节流和函数去抖。这篇文章不会涉及具体的代码实现(关于代码实现请期...

    ZHAO_ 评论0 收藏0
  • JavaScript专题系列文章

    摘要:专题系列共计篇,主要研究日常开发中一些功能点的实现,比如防抖节流去重类型判断拷贝最值扁平柯里递归乱序排序等,特点是研究专题之函数组合专题系列第十六篇,讲解函数组合,并且使用柯里化和函数组合实现模式需求我们需要写一个函数,输入,返回。 JavaScript 专题之从零实现 jQuery 的 extend JavaScritp 专题系列第七篇,讲解如何从零实现一个 jQuery 的 ext...

    Maxiye 评论0 收藏0
  • JavaScript专题系列20篇正式完结!

    摘要:写在前面专题系列是我写的第二个系列,第一个系列是深入系列。专题系列自月日发布第一篇文章,到月日发布最后一篇,感谢各位朋友的收藏点赞,鼓励指正。 写在前面 JavaScript 专题系列是我写的第二个系列,第一个系列是 JavaScript 深入系列。 JavaScript 专题系列共计 20 篇,主要研究日常开发中一些功能点的实现,比如防抖、节流、去重、类型判断、拷贝、最值、扁平、柯里...

    sixleaves 评论0 收藏0
  • 一次发现underscore源码bug的经历以及对学术界拿来主义的思考

    摘要:事情是如何发生的最近干了件事情,发现了源码的一个。楼主找到的关于和区别的资料如下关于拿来主义为什么这么多文章里会出现泽卡斯的错误代码楼主想到了一个词,叫做拿来主义。的文章,就深刻抨击了拿来主义这一现象。 事情是如何发生的 最近干了件事情,发现了 underscore 源码的一个 bug。这件事本身并没有什么可说的,但是过程值得我们深思,记录如下,各位看官仁者见仁智者见智。 平时有浏览别...

    Lionad-Morotar 评论0 收藏0

发表评论

0条评论

Flink_China

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<