前端面试高频问题之防抖,节流

219 阅读2分钟

场景

在进行窗口的resize、scroll,输入框内容校验等操作时,如果事件处理函数调用的频率无限制,会加重浏览器的负担,导致用户体验非常糟糕。此时我们可以采用debounce(防抖)和throttle(节流)的方式来减少调用频率,同时又不影响实际效果。

因频繁执行DOM操作,资源加载等行为,导致UI停顿甚至浏览器崩溃。

  • window对象频繁的onresize,onscroll等事件
  • 拖拽的mousemove事件
  • 射击游戏的mousedown,keydown事件
  • input文字输入,自动完成的keyup事件

防抖

函数防抖:将几次操作合并为一此操作进行。原理是维护一个计时器,规定在等待时间后触发函数,但是在等待时间内再次触发的话,就会取消之前的计时器而重新设置。这样一来,只有最后一次操作能被触发。好多文章的例子考虑了防抖节流函数存在参数的情况,但并没有传入参数。下面我们上一个完整版代码。 持续触发click事件时,并不执行fangdouFn函数,当1000毫秒内没有触发click事件时,才会延时触发click事件。

<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>防抖</title>
</head>
<body>
   <div id="fang" style="height: 200px; width: 200px; background: #73DE80"></div>
</body>
<script>
   var fangId = document.getElementById('fang')
   var testFD = fangdou(fangdouFn,1000)
   fangId.addEventListener('click', function (e){testFD(e)})
    function fangdou(fn,wait = 500) {
        let time
        return function () {
            if(time){
                clearTimeout(time)
            }
            time = setTimeout(()=>{
                fn.apply(this,arguments)
            },wait)
        }
    }
   function fangdouFn(e) {
       console.log(123,e)
   }
</script>
</html>

如果函数不传参数的话,可以直接这么写

   var fangId = document.getElementById('fang')
   fangId.addEventListener('click', fangdou(fangdouFn,1000))
    function fangdou(fn,wait = 500) {
        let time
        return function () {
            if(time){
                clearTimeout(time)
            }
            time = setTimeout(()=>{
                fn.apply(this,arguments)
            },wait)
        }
    }
   function fangdouFn() {
       console.log(123)
   }

节流

函数节流:使得一定时间内只触发一次函数。原理是通过一个标志位,用这个标志位判断函数知否执行,只有规定时间内函数执行之后,标志位改变状态才能进行下一次函数执行。

<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>节流</title>
</head>
<body>
<div id="fang" style="height: 200px; width: 200px; background: #73DE80"></div>
</body>
<script>
    var fangId = document.getElementById('fang')
    var testFD = jieliu(jieliuFn,1000)
    fangId.addEventListener('click', function (e){testFD(e)})
    function jieliu(fn,wait = 500) {
        let time = true
        return function () {
            if(time){
                time = false
                setTimeout(()=>{
                    time = true
                    fn.apply(this,arguments)
                },wait)
            }
        }
    }
    function jieliuFn(e) {
        console.log(123,e)
    }
</script>
</html>