去抖(3种场景)&节流

143 阅读1分钟
<!DOCTYPE html>
<html>
<head>
  <meta charset='utf-8'>
  <meta http-equiv='X-UA-Compatible' content='IE=edge'>
  <title>Page Title</title>
  <meta name='viewport' content='width=device-width, initial-scale=1'>
  <style>
    .btn-loading-circle:after{
      content: '\27F3';
      display: inline-block;
      animation: mrotate 1.6s linear infinite 0s;
    }
    @keyframes mrotate {
      100% {
        transform: rotate(1turn)
      }
    }
    
  </style>
</head>
<body>
  <h1>去抖:异步,立即,延迟</h1>
  <h2>去抖:1.异步执行(触发请求的点击)</h2>
  <h3>单个异步操作</h3>
  <button id="btnSingle">无状态变化</button>
  <button id="btnSingleLoading">带加载中状态</button>
  <h3>多个异步操作</h3>
  <button id="btnMultiple">无状态变化(如验证码倒计时)</button>
  <button id="btnMultipleLoading">带加载中状态(如验证码倒计时)</button>

  <h2>去抖:2.立即执行(触发动画或大量计算的操作,如转盘的点击旋转按钮)</h2>
  <button id="btnDebounceImmediate">去抖:2.立即执行</button>
  <a href="'http://demowap.lihaipeng.net/rotary/arr">线上示例</a>
  <h2>去抖:3.延迟执行(模糊搜索)</h2>
  <input id="inputDebounce">
  <a href="'http://demoweb.lihaipeng.net/rotary/">线上示例</a>

  <h1>节流:onresize&onscroll</h1>
  
  <script>
    // 去抖:异步,立即,延迟
    // 去抖:1.异步执行(触发请求的点击)
    const btnSingle = document.getElementById('btnSingle')
    const btnSingleLoading = document.getElementById('btnSingleLoading')
    const btnMultiple = document.getElementById('btnMultiple')
    const btnMultipleLoading = document.getElementById('btnMultipleLoading')

    btnSingle.onclick = debounceAsync(async () => {
      console.log('btnSingle')
      await requestApi()
    })
    btnSingleLoading.onclick = debounceAsync(async (e) => {
      console.log('btnSingleLoading')
      const self = e.target
      self.classList.add("btn-loading-circle");
      await requestApi()
      self.classList.remove("btn-loading-circle");
    })

    btnMultiple.onclick = debounceAsync(async (e) => {
      console.log('btnMultiple')
      const self = e.target
      await requestApi()
      await countdownSeconds(seconds => {
        self.innerHTML = seconds === 0 ? '重新发送' : seconds+'s'
      },6)
    })
    btnMultipleLoading.onclick = debounceAsync(async (e) => {
      console.log('btnMultipleLoading')
      const self = e.target
      self.classList.add("btn-loading-circle");
      await requestApi()
      self.classList.remove("btn-loading-circle");
      await countdownSeconds(seconds => {
        self.innerHTML = seconds === 0 ? '重新发送' : seconds+'s'
      },6)
    })

    // 去抖:1.异步
    function debounceAsync(func) {
      let isDisable = false
      return async function () {
        if (isDisable === true) return
        isDisable = true
        await func.apply(this, arguments)
        isDisable = false
      }
    }
    // 倒计时读秒
    function countdownSeconds(setSeconds, totalSecond = 60) {
      return new Promise((resolve) => {
        let seconds = totalSecond;
        const timer = setInterval(() => {
          if (seconds === 0) {
            clearInterval(timer)
            resolve()
            senonds = totalSecond
          }
          setSeconds(seconds)
          seconds--
        }, 1000)
      })
    }




    // 去抖:2.立即执行(触发动画或大量计算的操作,如转盘的点击旋转按钮)
    const btnDebounceImmediate = document.getElementById('btnDebounceImmediate')
    btnDebounceImmediate.onclick = debounceImmediate(() => { console.log('debounceImmediate')})
    // 去抖:立即执行(按钮连点请求)
    function debounceImmediate(func, wait = 2000) {
      let previous = 0;
      return function () {
        const now = +new Date()
        const remaining = previous + wait - now
        if (previous === 0 || remaining <= 0) {
          previous = now
          func.apply(this, arguments)
        }
      }
    }


    // 去抖:3.延迟执行(模糊搜索)
    const inputDebounce = document.getElementById('inputDebounce')
    inputDebounce.oninput = debounce(async (e) => {
      const self = e.target
      console.log('inputDebounce', self.value)
      await requestApi()
    })
    // 去抖:延迟执行,最后一次推迟wait(模糊搜索框输入过程中)
    function debounce(func, wait = 1500) {
      let timer = null;
      return function () {
        if (timer) clearTimeout(timer)
        timer = setTimeout(() => {
          func.apply(this, arguments)
          timer = null
        }, wait)
      }
    }

    // 节流:onresize&onscroll
    window.onresize = throttle(() => console.log('throttle onresize'), 2000)
    window.onscroll = throttle(() => console.log('throttle onscroll'), 2000)
    // window.onresize = () => console.log(123)
    // 节流:立即执行+延迟执行,最后一次保持间隔执行(浮动轴事件,窗口大小变动)
    function throttle(func, wait = 1000) {
      let previous = 0;
      let timer = null
      return function () {
        const now = +new Date()
        const remaining = previous + wait - now
        if (previous === 0 || remaining <= 0) {
          previous = now
          func.apply(this, arguments)
        } else if (!timer) {
          timer = setTimeout(() => {
            clearTimeout(timer)
            timer = null
            func.apply(this, arguments)
          }, remaining)
        }
      }
    }


    async function requestApi() {
      return new Promise(async resolve => {
        // mock
        console.log('requestApi start')
        setTimeout(() => {
          const data = {}
          resolve(data)
          console.log('requestApi end')
        }, 1000)
        return

        const response = await getWalletInfo()
        console.log('response---:', response)
        resolve(response)
      })
    }
  </script>
</body>
</html>