前端百题——通俗易懂的防抖与节流

 

性能一直是前端老生常谈的一个话题,其中有一个性能问题就是咱们会频繁的触发一些事件,例如mousemove、scroll、resize等,虽然浏览器已经对这些事件的触发作了一些优化,可是若是在很短的时间内频繁的触发仍然会影响性能,这个时候就须要今天的主角:防抖和节流,利用它们来进行优化,提升性能。前端

21.1 防抖

img

21.1.1 定义

防抖就是将屡次高频操做优化为只在最后一次执行(某个函数在某段时间内,不管触发了多少次回调,都只执行最后一次)。一般的使用场景是:用户输入,只需在输入完成后作一次输入校验便可。浏览器

21.1.2 实现

防抖是将屡次操做合并为一次操做完成,其原理就是维护一个计时器,在规定的时间后触发函数,可是在该规定时间内再次触发的话就会取消以前的定时器而从新设置,从而保证了只有最后一次操做可以被触发。其实现步骤以下所示:闭包

  1. 利用闭包保存一个timer变量,而后返回一个函数(这个返回的函数就是后续频繁触发操做中调用的函数);
  2. 根据标志位判断是否第一次须要当即执行(由于有些状况是须要首次调用函数当即执行的,若没有该参数,就会在定时器到了以后才会执行);
  3. 当有新的触发时,若存在定时器,则清空该定时器;
  4. 设定一个新的定时器,从新计时。
function debounce(fn, wait, immediate) {
        let timer = null;
        return function (...args) {
            // 当即执行的功能(timer为空表示首次触发)
            if (immediate && !timer) {
                fn.apply(this, args);
            }

            // 有新的触发,则把定时器清空
            timer && clearTimeout(timer);
            // 从新计时
            timer = setTimeout(() => {
                fn.apply(this, args);
            }, wait);
        }
    }
复制代码

21.1.3 效果预览

防抖.gif

观察效果图能够验证上述的理论知识:app

  1. 防抖以后输出内容的频次下降了;
  2. 防抖以后,其在超过必定时间以后才会输出内容。

21.2 节流

img

21.2.1 定义

节流就是每隔一段时间后执行一次,也就是下降频率,将高频操做优化成低频操做。一般使用场景:滚动条事件、resize事件、动画等,一般每隔100-500ms执行一次便可。ide

21.2.2 实现

节流函数的实现方式有两种:定时器版本、时间戳版本,这二者各有千秋,下面来简要实现一下。函数

21.2.2.1 定时器版本性能

定时器版本的节流函数其重点是利用闭包保存timer变量,具备两个特色:优化

  1. n秒后才会执行第一次(定时器到了时间后才会触发);
  2. 中止触发后节流函数还会执行一次(由于该函数是延迟执行的,当中止触发时其任务已经到了队列中,因此中止后还会执行一次)。
// 定时器版本
function throttle(fn, wait) {
    let timer = null;
    return function(...args) {
        if (!timer) {
            timer = setTimeout(() => {
                fn.apply(this, args);
                timer = null;
            }, wait)
        }
    }
}
复制代码

21.2.2.2 时间戳版本动画

时间戳版本的节流函数重点是利用闭包保存上一次的时间previous,具备两个特色:this

  1. 开始触发后会当即执行(由于previous开始会被赋值为0);
  2. 中止触发后再也不执行(由于该函数是同步任务,在触发的时候就会进行相应的判断,因此就不存在中止触发后再执行的状况)。
// 时间戳版本
function throttle(fn, wait) {
    // 上一次执行时间
    let previous = 0;
    return function(...args) {
        // 当前时间
        let now = +new Date();
        if (now - previous > wait) {
            previous = now;
            fn.apply(this, args);
        }
    }
}
复制代码

21.2.3 效果预览

节流.gif

观察效果图能够验证上述的理论知识:

  1. 节流确实下降了内容的输出频率,将高频变为低频;
  2. 时间戳版本的节流函数在首次会输出内容,可是最后一次的内容不会输出(谨慎使用);
  3. 定时器版本的节流函数确实不会马上打印内容,而是超过必定时间以后才会打印;此外,其最后输入的内容会被打印出来。
相关文章
相关标签/搜索