防抖节流

背景问题

在前端开发中有一部分的用户行为会频繁的触发事件,从而频繁地执行函数,而对于DOM操作、资源加载等耗费性能的处理,很可能导致界面卡顿,甚至浏览器崩溃(本质是因为js是单线程的)。

函数节流(throttle)和函数防抖(debounce)可以解决问题。

防抖

函数防抖就是在函数需要频繁触发情况时,只有等足够空闲的事件,才执行,为了避免又有事件触发。

  • 常见应用场景:搜索框实时搜索请求数据、拖拽
  • 代码实现:

关键点:设置定时器、this的指向、arguments的指向

模拟搜索框实时请求数据👇

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var oInp = document.getElementById('inp');

var timer = null;

oInp.oninput = function (e) {
// console.log(arguments);
var _self = this;//想要的是输入框input的数据,若无此步,setTimeout的this指向window
var _arg = arguments;
clearTimeout(timer);
timer = setTimeout(function () {
ajax.apply(_self, _arg)//改变this指向,让输入框元素实际调用这个函数
}, 1000)
};
function ajax(e) {
console.log(e, this.value);
}

上面的代码只能应对发送ajax这种业务,下面进行一下防抖的封装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var oInp = document.getElementById('inp');
function ajax(e) {
console.log(e, this.value);
}

function debounce(handler, delay) {
// handler 要进行防抖处理的功能性函数
// delay 延迟时间
var timer = null;
return function () {
var _self = this;
var _arg = arguments;
clearTimeout(timer);
timer = setTimeout(function () {
handler.apply(_self, _arg)
}, delay);
}
}

oInp.oninput = debounce(ajax, 2000);

节流

函数节流就是预定一个函数只有在大于或等于执行周期时才执行,周期内调用不执行。

  • 常见应用场景
    • 窗口调整
    • 页面滚动数据加载
    • 防止恶意脚本抢购疯狂点击
  • 代码实现

    模拟抢红包的功能👇

    1571146823113

    这种代码如果被人注入恶意脚本,使得按钮点击事件疯狂触发,服务器和客户端都受不了。为了避免这种情况,使用节流操作。

    1
    2
    我抢到<span id="show">0</span>个红包!
    <button id="btn">点击</button>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
      
    var oSpan = document.getElementById('show');
    var oBtn = document.getElementById('btn');

    // oBtn.onclick = function () {
    // oSpan.innerText = parseInt(oSpan.innerText) + 1;
    // }
    oBtn.onclick = throttle(function () {
    oSpan.innerText = parseInt(oSpan.innerText) + 1;
    }, 1000)

    function throttle(handler, wait) {
    var lastTime = 0;
    return function () {
    var nowTime = new Date().getTime();
    if (nowTime - lastTime > wait) {
    handler();
    lastTime = nowTime;
    }
    }
    }

    再改进一下👇

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    var oSpan = document.getElementById('show');
    var oBtn = document.getElementById('btn');

    oBtn.onclick = throttle(crazyClick, 1000)

    function throttle(handler, wait) {
    var lastTime = 0;
    return function (e) {
    var nowTime = new Date().getTime();
    if (nowTime - lastTime > wait) {
    handler.apply(this, arguments);
    lastTime = nowTime;
    }
    }
    }

    function crazyClick(e) {
    console.log(this, e);
    oSpan.innerText = parseInt(oSpan.innerText) + 1;
    }


假设无限次触发:防抖函数永远不会真正执行;节流函数则会按照间隔时间执行。

防抖动和节流本质是不一样的。防抖动是将多次执行变为最后一次执行,节流是将多次执行变成每隔一段时间执行。