JS节流函数的三种形态.

157 阅读1分钟

前言:节流一共有三种形态,不同的需求下,需要使用不同的形态,在此处对三种形态进行分解记录.本文为了让新手玩家更易理解,未使用apply,arguments参数传递等相关内容,高手可以自行补充. 最后有【完整代码】,可直接复制到html运行.

第一形态(首次触发延迟):点击【并不会立即触发】,需要等待设置的节流时间结束,然后【触发】.

function throttle1(fn, wait) {
  let timer = null;
  return function () {
    if (!timer) {
      timer = setTimeout(() => {
        timer = null;
        fn()
      }, wait);
    }
  }
}

第二形态(末尾一次不触发):点击【立即触发】,在节流冷却时间内多次点击,将直接被忽略,冷却结束时,【不会触发】.

function throttle2(fn, wait) {
  let pre = 0;
  return function () {
    let now = Date.now()
    if (now - pre > wait) {
      fn()
      pre = now
    }
  }
}

第三形态:点击【立即触发】,在节流冷却时间内多次点击,将被缓存,冷却结束时,【立即解发】.

function throttle3(fn, wait) {
  let timer = null;
  let pre = 0;
  return function () {
    let now = Date.now();
    if (now - pre > wait) {
      if (timer) {
        clearTimeout(timer)
        timer = null
      }
      fn()
      //记录最后一次触发时间
      pre = now
    } else if (!timer) {
      //当前还不可触发,则缓存一次等触发.
      timer = setTimeout(() => {
        fn();
        timer = null
        pre = Date.now();
      }, wait)
    } else {
      console.log(`此时,还在触发等待期,并且缓存中还有等执行,则啥也不做.`);
    }
  }
}

以下是完整html代码,可直接运行

<!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>Document</title>
</head>

<body>
  <div id="button" style="padding: 40px;background-color: aqua;cursor: pointer;">点我触发</div>
</body>


<script>
  //节流 定时器 (最后一次也触发)
  function throttle1(fn, wait) {
    //弊端,第一下不会立即触发.
    let timer = null;
    return function () {
      if (!timer) {
        timer = setTimeout(() => {
          timer = null;
          fn()
        }, wait);
      }
    }
  }


  //节流 时间戳 (第一次就触发)
  function throttle2(fn, wait) {
    //弊端,最后一下,并不会触发.
    let pre = 0;
    return function () {
      let now = Date.now()
      if (now - pre > wait) {
        fn()
        pre = now
      }
    }
  }

  //节流 控制最后一次和第一次
  function throttle3(fn, wait) {
    let timer = null;
    let pre = 0;
    return function () {
      let now = Date.now();
      if (now - pre > wait) {
        if (timer) {
          clearTimeout(timer)
          timer = null
        }
        fn()
        //记录最后一次触发时间
        pre = now
      } else if (!timer) {
        //当前还不可触发,则缓存一次等触发.
        timer = setTimeout(() => {
          fn();
          timer = null
          pre = Date.now();
        }, wait)
      } else {
        console.log(`此时,还在触发等待期,并且缓存中还有等执行,则啥也不做.`);
      }
    }
  }

  const func = throttle3(() => {
    console.log('节流函数触发啦');
  }, 1000);
  document.querySelector('#button').addEventListener('click', () => {
    console.log('用户点击了按钮');
    func()
  })
</script>


</html>