函数防抖


什么是函数函数防抖

函数防抖: 其实概念很简单,就两句话。
第一句:函数执行过一次后,在等待某时间段内不能再次执行
第二句: 在等待时间内触发此函数,则重新计算等待时间
这两句话既是函数防抖的定义,也是函数防抖的原理。lodash中的_.bounce就是围绕这两句话写的, 后面会给大家讲解。

换句通俗的话说,就是:你尽管触发事件,但是我一定在事件触发n秒后才执行,如果你在一个事件触发的n秒内又触发了这个事件,那我就以新的事件的时间为准,n秒后才执行,总之,就是要等你触发完事件n秒内不再触发事件,我才执行,真是任性呐。

如果不理解上面定义,我可以再给大家举个生活例子:
如果有人进电梯(触发事件),那电梯将在10s出发(执行事件句柄),这时如果又有人进电梯了(在10s内再次触发该事件),我们又得等10s再出发(重新计时)。这个例子很完美的展示了函数防抖的精髓。

函数防抖使用场景

现在,大家可以很容易理解什么是函数防抖了吧。结合刚才的生活例子,可以想象下,在我们前端界有哪些是函数防抖的使用场景:

  • 每次 resize/scroll 触发统计事件
  • 文本输入验证(连续输入文字后发生AJAX请求进行验证,验证一次就好)
  • mousemove,mousedown
  • 加载更多(这个与前2个还是有点区别)

函数防抖的封装:

第一版:

我们先以函数被执行过一次后,在等待某时间段内不能再次执行原理,封装一个简单的函数防抖:
先假设函数的定义形式为:

window.onscroll = _debounce(function(){
  console.log(1);
}, 500);
function _debounce(func, wait) {
  var timer = null;
  var context, args;
  return function () {
     context = this; 
     args = arguments;
    clearTimeout(timer);
    timer = setTimeout(function() {
      func.apply(context, args);
    }, wait);
  }
}

通过调用_debounce, 返回一个闭包函数。在连续调用_debounce时,只会在最后一次触发的时候执行回调,这是因为每次调用, 都会通过clearTimeout会清掉上一个timer。

现在仔细想想,这个封装貌似有个问题:如果我想在第一次触发的时候执行回调呢?这种场景是不是很适合加载更多场景?因为从体验方面看,我们希望第一次触发加载更多的时候,就执行回调。而不是在最后一次触发的时候执行回调。如果我们一直滚动页面,那加载更多就一直不触发...这种体验是不是很糟糕。

基于上面问题,我们再次进行封装,多添加一个参数。
现假设函数的定义形式为:

window.onscroll = _debounce(function(){
    console.log(1);
}, 500, true);
function _debounce(func, wait, immediate) {
    var timer = null;
    var context, args, result, timestamp;

    var later = function() {
        var oDate = new Date();
        var last = oDate.getTime() - timestamp; // 计算第一次时间戳与当前时间戳的差值。

        if (last < wait && last >= 0) { // 在等待时间内触发此函数,重新计时。
            timer = setTimeout(later, wait - last);
        } else {
            timer = null;
            if(!immediate) { // 限制immediate 为true时,执行回调函数。
                result = func.apply(context, args);
                if(!timer) context = args = null;
            }
        }
    }

    return function() {
        var oDate = new Date();  
        var callNow = immediate && !timer; // 代表第一次调用立即执行。
      
        timestamp = oDate.getTime(); // 记录下当前时间戳
        context = this; // 保存上下文
        args = arguments; 
    
        if(!timer) { // 第一次触发时,timer为空,进入此分支
            timer = setTimeout(later, wait);
        }

        if(callNow) { // 第一次触发且immediate为true,进入此分支
            result = func.apply(context, args);
            context = args = null;  
        }
        
        return result;
    }
}

此次封装支持两种形式:
immediate为true时,连续事件触发时,只会在第一次触发的时候执行回调。
immediate为false时,连续事件触发时,只会在最后一次触发的时候执行回调。

参考文献:
https://github.com/mqyqingfeng/Blog/issues/22

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,635评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,628评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,971评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,986评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,006评论 6 394
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,784评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,475评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,364评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,860评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,008评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,152评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,829评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,490评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,035评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,156评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,428评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,127评论 2 356

推荐阅读更多精彩内容

  • 函数节流 还记得上篇文章中说到的图片懒加载吗?我们在文章的最后实现了一个页面滚动时按需加载图片的方式,即在触发滚动...
    柏丘君阅读 2,848评论 1 19
  • 概念 函数防抖(debounce) 当调用动作过n毫秒后,才会执行该动作,若在这n毫秒内又调用此动作则将重新计算执...
    BULL_DEBUG阅读 1,263评论 0 0
  • 函数防抖与节流,网上的内容参差不齐,很容易弄混淆,本文不针对定义来说明什么是防抖,什么是节流,直接 show me...
    DCbryant阅读 606评论 0 0
  • debounce -- 函数防抖,throttle -- 函数节流都是在JavaScript中可以限制函数发生频率...
    Quilljou阅读 436评论 0 3
  • 写在前面的话 这是上个月注册了简书后写的第二篇文章,关于梦想。那时提笔,绞尽脑汁只憋得出800字。转眼一个月过去,...
    王茯苓阅读 482评论 2 9