性能优化之 防抖与节流的原理

面试中经常遇到面试官问到,手写一个防抖或者节流吧。
这道题真是说容易也容易,说不容易也不容易的题。

如果你没有自己仔细的研究过,甚至连二者的差别都说不清楚 ,就更别提手写出代码来了。


说的啥.jpg

那下面我们就一起来学习一下防抖和节流分别是什么功能,它们俩又是如何实现的呢。

节流

节流就是控制流量,在某段时间内,只执行一次。

防抖

某段时间内未结束操作,则重新计时,并在规定时间内,仅执行一次。
看起来感觉差不多,
比如浏览器的onscroll,oninput,resize,onkeyup等,如果用户一直操作滚动视窗、缩放浏览器大小,则会重新计算延时,若操作稳定了,则在约定时间后执行一次方法。


多说无益.jpg

行吧。下面先实现一个简单版本的节流:

/**
 @func 要节流的函数
 @wait 时间间隔
*/
function throttle(func, wait){
  let pre = 0;//记录上一次的时间
  return function(){
      let now = Date.now();//记录当前时间
     if(now - pre > wait){ //如果时间差大于约定的时间间隔
       func.apply(this, arguments); //则触发
      pre = now; //同时将时间更新
    }
  }
}

参考代码:Easy Throttle

上面是利用时间戳的方式实现,有一个问题存在,第一次触发会执行func,但停止触发后,不会再执行一次func。
我们试着使用定时器来优化一下,并将停止触发后要不要再执行一次作为一个参数trailing传递。

 function throttle(func, wait, options) {
  let args, context;
  let pre = 0;
  let timer;
  let later = function () {
    pre = Date.now();
    func.apply(context, args);
    args = context = null;
  };

  let throttled = function () {
    args = arguments;
    context = this;
    let now = Date.now();

    let remaining = wait - (now - pre);
    if (remaining <= 0) {
      //第一次执行,如果已经存在,则清除
      if (timer) {
        clearTimeout(timer);
        timer = null;
      }
      func.apply(context, args);
      pre = now;
    } else if (!timer && options.trailing !== false) {
      //默认会触发,最后一次应该触发。
      timer = setTimeout(later, remaining);
    }
  };

  return throttled;
}

调用时:

let btn = document.getElementById("btn");
btn.addEventListener("click", throttle(logger, 1000, { trailing: true })); //1s内都算一次
function logger() {
  console.log("logger");
}

参考代码:停止触发后要不要再次执行

那么既然有限制停止触发后的再次执行,就有对于首次加载时需不需要立即执行的限制,这里我们用参数leading:false来表示一进来不要立即执行。

function throttle(func, wait, options){
    let args,context;
    let pre = 0;
    let timer;
    let later = function(){
        pre = options.leading === false ? 0:Date.now();
        func.apply(context, args);
        args = context = null;

    }
    let throttled = function (){
        args = arguments;
        context = this;
        let now = Date.now();
      
        //一进来不要立刻执行
        if(!pre && options.leading === false){
            pre = now;
        }

        let remaining = wait - (now - pre);
        if(remaining <= 0){//第一次执行
            if(timer){
                clearTimeout(timer);
                timer = null;
            }
            func.apply(context, args);
            pre = now;
        }else if(!timer && options.trailing !== false){//默认会触发,最后一次应该触发。
            timer = setTimeout(later, remaining);
        }
    }

    return throttled;
}

调用时:

let btn = document.getElementById("btn");
btn.addEventListener("click", throttle(logger, 1000, { leading: false })); 
function logger() {
  console.log("logger");
}

参考代码:是否立即执行

防抖:

function debounce(func, wait, immediate){
    let timer;
    return function(){
        clearTimeout(timer);
        if(immediate){
            let callNow =!timer; 
            if(callNow) func.apply(this, arguments);
        }
        timer = setTimeout(()=>{
            func.apply(this, arguments)
            timer = null;
        }, wait);
    }
}

调用时:

let btn2 = document.getElementById('btn2');
btn2.addEventListener('click',debounce(logger,1000, true)); //停止 时才算一次
function logger(e){
    console.log('logger2',e);
}

参考代码:debounce

好啦,笔记 就写到这里,后续可能会补充一下lodash关于二者合到一起的写法。
今天就点到为止吧。

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