手写防抖节流

文章目录

  • 手写前端常用技巧-防抖节流
  • 防抖
  • 节流
    • 1. 首节流
    • 2. 尾节流
    • 3. 首尾节流
  • 总结


手写前端常用技巧-防抖节流

防抖:当持续触发事件时,一定时间内没有再触发事件,才会在一段时间之后触发事件处理函数。

节流:当持续触发事件时,保证一段delay之内,只调用一次函数

防抖

  • 源代码
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>防抖title>
head>
<body>
    <label for='undebounce'>没防抖:label>
    <input type="text" id='undebounce' onInput='onInput1(event)' >
    <br />
    <label for="debounce">有防抖:label>
    <input type="text" id='debounce' onInput='debounceInput(event)' >

    <script>
        function debounce(fn, delay){
            let time = null
            return function(...args){
                if(time){
                    clearTimeout(time)
                }
                time = setTimeout(()=>{
                    fn.apply(this, args)
                },delay)
            }
        }
        function onInput(e){
            val = e.target.value
            if(val){
                console.log('有防抖',val)
            }
        }

        const debounceInput = debounce(onInput, 300)

        function onInput1(e){
            val = e.target.value
            if(val){
                console.log('没有防抖',val)
            }
        }
    script>
body>
html>
  • 执行结果

手写防抖节流_第1张图片

::: tip

  • 结果分析
  1. 没有防抖的输入框持续输入时,每键入一个字母都执行一次处理函数
  2. 有防抖的输入框持续输入时,在键入字母结束之后才执行一次处理函数

:::

节流

1. 首节流

首节流,时间戳的实现,首次触发立即执行,停止触发后,没办法再次执行

  • 源代码
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>节流throttletitle>
head>
<body>
    <ul>
        <li>1li>
        <li>2li>
        <li>3li>
        <li>4li>
        <li>5li>
        <li>6li>
        <li>7li>
        <li>8li>
        <li>9li>
        <li>1li>
        <li>2li>
        <li>3li>
        <li>4li>
        <li>5li>
        <li>6li>
        <li>7li>
        <li>8li>
        <li>9li>
    ul>
body>
<style>
    body{
        display: flex;
        justify-content: center;
    }
    ul, li {
        padding:0;
        margin: 0;
    }
    li{
        width: 250px;
        height:200px;
        list-style: none;
        display: flex;
        justify-content: center;
        align-items: center;
    }
    li:nth-child(2n){
        background:whitesmoke;
    }
    li:nth-child(2n+1){
        background:yellow;
    }
style>
<script>
    // 首节流,时间戳的实现,停止触发后,没办法再次执行

    function throttle(fn, interval){
        let prev = 0;
        return function(...args){
            const now = Date.now();
            if( now-prev >= interval ){
                prev = now
                fn.apply(this, args)
            }
        }
    }
    function handle(){
        console.log(new Date())
    }

    const throttleHandler = throttle(handle, 3000)
    console.log('tt', throttleHandler)
    window.addEventListener('scroll', throttleHandler)
script>
html>

手写防抖节流_第2张图片

可以看到,只要滑动了,就会触发事件,但是停止滑动之后,不会触发最后一次。

2. 尾节流

定时器实现,不会立即执行,而是在delay之后执行

最后停止触发之后,还会执行一次

  • 源代码
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>节流throttletitle>
head>
<body>
    <ul>
        <li>1li>
        <li>2li>
        <li>3li>
        <li>4li>
        <li>5li>
        <li>6li>
        <li>7li>
        <li>8li>
        <li>9li>
        <li>1li>
        <li>2li>
        <li>3li>
        <li>4li>
        <li>5li>
        <li>6li>
        <li>7li>
        <li>8li>
        <li>9li>
    ul>
body>
<style>
    body{
        display: flex;
        justify-content: center;
    }
    ul, li {
        padding:0;
        margin: 0;
    }
    li{
        width: 250px;
        height:200px;
        list-style: none;
        display: flex;
        justify-content: center;
        align-items: center;
    }
    li:nth-child(2n){
        background:whitesmoke;
    }
    li:nth-child(2n+1){
        background:yellow;
    }
style>
<script>
    // 尾节流,定时器实现,不会立即执行,而是在delay之后执行
    // 最后停止触发之后,还会执行一次
    function throttle(fn,delay){
        let timer = null
        return function(...args){
            if( !timer ){
                timer = setTimeout(()=>{
                    fn.apply(this, args)
                    timer = null
                }, delay)
            }

        }
    }

    function handle(){
        console.log(new Date())
    }

    const throttleHandler = throttle(handle, 3000)
    console.log('tt', throttleHandler)
    window.addEventListener('scroll', throttleHandler)
script>
html>

手写防抖节流_第3张图片

可以看到我们停止滑动之后还是触发了事件

3. 首尾节流

  • 源代码
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>节流throttletitle>
head>
<body>
    <ul>
        <li>1li>
        <li>2li>
        <li>3li>
        <li>4li>
        <li>5li>
        <li>6li>
        <li>7li>
        <li>8li>
        <li>9li>
        <li>1li>
        <li>2li>
        <li>3li>
        <li>4li>
        <li>5li>
        <li>6li>
        <li>7li>
        <li>8li>
        <li>9li>
    ul>
body>
<style>
    body{
        display: flex;
        justify-content: center;
    }
    ul, li {
        padding:0;
        margin: 0;
    }
    li{
        width: 250px;
        height:200px;
        list-style: none;
        display: flex;
        justify-content: center;
        align-items: center;
    }
    li:nth-child(2n){
        background:whitesmoke;
    }
    li:nth-child(2n+1){
        background:yellow;
    }
style>
<script>
    // 首尾节流,计时器+时间戳
    function throttle(fn, delay){
        let timer = null
        let startTime = 0
        return function(...args){
            let curTime = Date.now();
            let remaining = delay - (curTime - startTime)
            // 清除旧的计时器
            clearTimeout(timer)

            if(remaining <= 0 ){
                fn.apply(this, args)
                startTime = Date.now()
            }else{
                timer = setTimeout(()=>{
                    fn.apply(this, args)
                    startTime = Date.now()
                }, remaining)
            }

        }
    }


    function handle(){
        console.log(new Date())
    }

    const throttleHandler = throttle(handle, 500)
    console.log('tt', throttleHandler)
    window.addEventListener('scroll', throttleHandler)
script>
html>

手写防抖节流_第4张图片

在这里我们缩短节流时间,方便看效果。

可以看到每次滑动都至少触发两次事件,即首尾触发

总结

虽然防抖和节流都是避免同一时间频繁执行处理函数,但是原理却有一些差别

::: note

应用场景

  • 防抖 debounce

    • search搜索联想,用户在不断输入值时,用防抖来节约请求资源。
    • window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次
  • 节流 throttle

    • 鼠标不断点击触发,mousedown(单位时间内只触发一次)
    • 监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断

:::

文章详细信息,请查看个人博客

你可能感兴趣的:(前端学习系列,html,css,html5)