# 手写节流

# 定义

n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效

# 代码实现

设计思路:我们可以设计一种类似控制阀门一样定期开放的函数,事件触发时让函数执行一次,然后关闭这个阀门,过了一段时间后再将这个阀门打开,再次触发事件。 刚开始valid为true,然后将valid重置为false,进入了定时器,在定时器的时间期限之后,才会将valid重置为true,valid为true之后,之后的点击才会生效 在定时器的时间期限内,valid还没有重置为true,会一直进入return,就实现了在N秒内多次点击只会执行一次的效果

function throttle(fn, delay){
	let valid = true;
	return function(){
		if(valid) { //如果阀门已经打开,就继续往下
			setTimeout(()=> {
				fn.apply(this, arguments);//定时器结束后执行
				valid = true;//执行完成后打开阀门
			}, delay)
			valid = false;//关闭阀门
		}
	}
}

# 生产实践

拖拽元素

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>throttle</title>
  </head>
  <body>
    <p>throttle</p>
    <div
      id="div1"
      draggable="true"
      style="width: 100px; height: 50px; background-color: #ccc; padding: 10px"
    >
      可拖拽
    </div>

    <script>
      // function throttle(fn, delay = 100) {
      //     let timer = 0

      //     return function () {
      //         if (timer) return

      //         timer = setTimeout(() => {
      //             fn.apply(this, arguments)
      //             timer = 0
      //         }, delay)
      //     }
      // }

      function throttle(fn, delay = 500) {
        let valid = true
        return function () {
          if (valid) {
            //如果阀门已经打开,就继续往下
            setTimeout(() => {
              fn.apply(this, arguments) //定时器结束后执行
              valid = true //执行完成后打开阀门
            }, delay)
            valid = false //关闭阀门
          }
        }
      }

      const div1 = document.getElementById('div1')
      div1.addEventListener(
        'drag',
        throttle((e) => {
          console.log('鼠标的位置', e.offsetX, e.offsetY)
        })
      )
    </script>
  </body>
</html>