JS手写防抖和节流函数(超详细版整理)

这篇具有很好参考价值的文章主要介绍了JS手写防抖和节流函数(超详细版整理)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1、什么是防抖和节流

防抖(debounce):每次触发定时器后,取消上一个定时器,然后重新触发定时器。防抖一般用于用户未知行为的优化,比如搜索框输入弹窗提示,因为用户接下来要输入的内容都是未知的,所以每次用户输入就弹窗是没有意义的,需要等到用户输入完毕后再进行弹窗提示。

节流(throttle):每次触发定时器后,直到这个定时器结束之前无法再次触发。一般用于可预知的用户行为的优化,比如为scroll事件的回调函数添加定时器。

2、使用场景

防抖在连续的事件,只需触发一次回调的场景有:

1.搜索框搜索输入。只需用户最后一次输入完,再发送请求

2.手机号、邮箱验证输入检测

3.窗口大小resize。只需窗口调整完成后,计算窗口大小。防止重复渲染。

节流在间隔一段时间执行一次回调的场景有:

1.滚动加载,加载更多或滚到底部监听

2.搜索框,搜索联想功能

3、手写防抖函数

1、函数初版

1.接收什么参数?

参数1: 回调函数
参数2: 延迟时间
function mydebounce(fn, delay){

}

2.返回什么

最终返回结果是要绑定对应的 监听事件,所以一定是个新函数
function mydebounce(fun, delay) {
const _debounce = () => {

}
return _debounce
}

3.内部怎么实现

可以在 _debounce 函数中开启一个定时器,定时器的延迟时间就是 参数delay
每次开启定时器时,都需要将上一次的定时器取消掉
function mydebounce(fn, delay){
    // 1. 创建一个变量,记录上一次定时器
    let timer = null
    
    // 2. 触发事件时执行函数
    const _debounce = () => {
        // 2.1 取消上一次的定时器,(第一次执行时,timer应该为null)
        if(timer) clearTimeout(timer)

        // 2.2 延迟执行传入fn的回调
        timer = setTimeout(() => {
            fn()
            // 2.3 函数执行完成后,需要将timer重置
            timer = null
        },delay)
    }

    return _debounce
}
以上,一个基本的防抖函数就实现了

对其进行测试

<!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>
    <input type="text">
    <script src="./防抖.js"></script>
    <script>
        const inputDOM = document.querySelector("input")

        let counter = 1;
        function searchChange(){
            console.log(`第${counter++}次请求`,this.value,this);
        }

        inputDOM.oninput = mydebounce(searchChange,500)
    </script>
</body>
</html>
手写防抖,实战记录,前端,javascript,vue.js,前端,Powered by 金山文档
在上面的测试中,当我们持续在input框中输入数据时,控制台只会每隔500ms进行输出

2、优化

虽然上面实现了基本的防抖函数,但是我们会发现代码中this的指向是window,而window没有value值,所以无法知道事件的调用者

A. 优化this

function mydebounce(fn, delay){
    let timer = null
    
    // 1. 箭头函数不绑定this,修改为普通函数
    const _debounce = function(){
        if(timer) clearTimeout(timer)

        timer = setTimeout(() => {
            // 2. 使用显示绑定apply方法
            fn.apply(this)
            timer = null
        },delay)
    }

    return _debounce
}
手写防抖,实战记录,前端,javascript,vue.js,前端,Powered by 金山文档

B.优化参数

在事件监听的函数,是有可能传入一些参数的,例如 event等

function mydebounce(fn, delay){
    let timer = null
    
    // 1. 接收可能传入的参数
    const _debounce = function(...args){
        if(timer) clearTimeout(timer)

        timer = setTimeout(() => {
            // 2. 将参数传给fn
            fn.apply(this,args)
            timer = null
        },delay)
    }

    return _debounce
}

测试:

    <script>
        const inputDOM = document.querySelector("input")

        let counter = 1;
        function searchChange(event){
            console.log(`第${counter++}次请求`,this.value, event);
        }

        inputDOM.oninput = mydebounce(searchChange,500)
    </script>
手写防抖,实战记录,前端,javascript,vue.js,前端,Powered by 金山文档

C.优化增加取消操作

为什么要增加取消操作呢?

例如,用户在表单输入的过程中,返回了上一层页面或关闭了页面,就意味着这次延迟的网络请求没必要继续发生了,所以可以增加一个可取消发送请求的功能

function mydebounce(fn, delay){
    let timer = null
    
    const _debounce = function(...args){
        if(timer) clearTimeout(timer)

        timer = setTimeout(() => {
            fn.apply(this,args)
            timer = null
        },delay)
    }

    // 给_debounce添加一个取消函数
    _debounce.cancel = function(){
        if(timer) clearTimeout(timer)
    }

    return _debounce
}

测试:

<body>
    <input type="text">
    <button>取消</button>
    <script src="./防抖.js"></script>
    <script>
        const inputDOM = document.querySelector("input")
        const btn = document.querySelector("button")

        let counter = 1;
        function searchChange(event){
            console.log(`第${counter++}次请求`,this.value, event);
        }
        
        const debounceFn= mydebounce(searchChange,500)
        inputDOM.oninput = debounceFn

        btn.onclick = function(){
            debounceFn.cancel()
        }
    </script>
</body>

D.优化增加立即执行

有些场景需要第一次输入时,立即执行,后续的输入再使用防抖

// 1.设置第三个参数,控制是否需要首次立即执行
function mydebounce(fn, delay, immediate = false){
    let timer = null
    
    // 2. 定义变量,用于记录状态
    let isInvoke = false

    const _debounce = function(...args){
        if(timer) clearTimeout(timer)

        // 3.第一次执行不需要延迟
        if(!isInvoke && immediate){
            fn.apply(this,args)
            isInvoke = true
            return
        }

        timer = setTimeout(() => {
            fn.apply(this,args)
            timer = null

            // 4.重置isInvoke
            isInvoke = false
        },delay)
    }

    _debounce.cancel = function(){
        if(timer) clearTimeout(timer)

        // 取消也需要重置
        timer = null
        isInvoke = false
    }

    return _debounce
}

测试:

<body>
    <input type="text">
    <button>取消</button>
    <script src="./防抖.js"></script>
    <script>
        const inputDOM = document.querySelector("input")
        const btn = document.querySelector("button")

        let counter = 1;
        function searchChange(){
            console.log(`第${counter++}次请求`,this.value);
        }

        
        const debounceFn= mydebounce(searchChange,1000,true)
        inputDOM.oninput = debounceFn

        btn.onclick = function(){
            debounceFn.cancel()
        }
    </script>
</body>
手写防抖,实战记录,前端,javascript,vue.js,前端,Powered by 金山文档

总结

基本函数

function mydebounce(fn, delay){
    let timer = null
    
    const _debounce = function(...args){
        if(timer) clearTimeout(timer)

        timer = setTimeout(() => {
            fn.apply(this,args)
            timer = null
        },delay)
    }

    return _debounce
}

考虑取消和立即执行的应用场景

function mydebounce(fn, delay, immediate = false){
    let timer = null

    let isInvoke = false

    const _debounce = function(...args){
        if(timer) clearTimeout(timer)

        if(!isInvoke && immediate){
            fn.apply(this,args)
            isInvoke = true
            return
        }

        timer = setTimeout(() => {
            fn.apply(this,args)
            timer = null
            isInvoke = false
        },delay)
    }

    _debounce.cancel = function(){
        if(timer) clearTimeout(timer)
        timer = null
        isInvoke = false
    }

    return _debounce
}

3、手写节流函数

  1. 函数初版

  1. 需要接受参数

参数1:要执行的回调函数
参数2:要执行的间隔时间
function myThrottle(fn, interval){

}
  1. 返回值

返回值为一个新的函数
function myThrottle(fn, interval){
const _throttle = function(){

}
return _throttle
}
  1. 内部实现

如果要实现节流函数,利用定时器不太方便管理,可以用时间戳获取当前时间nowTime
参数 : 开始时间 StartTime 和 等待时间waitTime,间隔时间 interval
waitTIme = interval - (nowTime - startTime)
得到等待时间waitTime,对其进行判断,如果小于等于0,则可以执行回调函数fn
开始时间可以初始化为0,第一次执行时,waitTime一定是负值(因为nowTime很大),所以第一次执行节流函数,一定会立即执行
function myThrottle(fn, interval){
    // 1. 定义变量,保存开始时间
    let startTime = 0

    const _throttle = function(){
        // 2. 获取当前时间
        const nowTime = new Date().getTime()
        // 3. 计算需要等待的时间
        const waitTime = interval - (nowTime - startTime)
        // 4.当等待时间小于等于0,执行回调
        if(waitTime <= 0){
            fn()
            // 并让开始时间 重新赋值为 当前时间
            startTime = nowTime
        }
    }
    
    return _throttle
}

测试:

<body>
    <input type="text">
    <script src="./节流.js"></script>
    <script>
        const input1 = document.querySelector("input")

        let counter = 1;
        function searchChange(){
            console.log(`第${counter++}次请求`,this.value);
        }

        input1.oninput = myThrottle(searchChange,500)
    </script>
</body>
手写防抖,实战记录,前端,javascript,vue.js,前端,Powered by 金山文档

2.优化

同样的,首先是对this指向和参数的优化

A.优化this指向和参数

function myThrottle(fn, interval){
    let startTime = 0

    const _throttle = function(...args){
        const nowTime = new Date().getTime()
        const waitTime = interval - (nowTime - startTime)
        if(waitTime <= 0){
            fn.apply(this,args)
            startTime = nowTime
        }
    }

    return _throttle
}
手写防抖,实战记录,前端,javascript,vue.js,前端,Powered by 金山文档

B.优化控制立即执行

上面的代码中,第一次执行 肯定是 立即执行的,因为waitTime第一次必为负数,但有时需要控制 第一次不要立即执行

// 1. 设置第三个参数控制是否立即执行
function myThrottle(fn, interval, immediate = true){
    let startTime = 0

    const _throttle = function(...args){
        const nowTime = new Date().getTime()
        
        // 2. 控制是否立即执行
        if(!immediate && startTime === 0){
            startTime = nowTime
        }

        const waitTime = interval - (nowTime - startTime)
        if(waitTime <= 0){
            fn.apply(this,args)
            startTime = nowTime
        }
    }

    return _throttle
}

测试:

    <script>
        const input1 = document.querySelector("input")

        let counter = 1;
        function searchChange(){
            console.log(`第${counter++}次请求`,this.value);
        }

        input1.oninput = myThrottle(searchChange,1000,false)
    </script>
手写防抖,实战记录,前端,javascript,vue.js,前端,Powered by 金山文档

总结

基本函数

function myThrottle(fn, interval){
    let startTime = 0

    const _throttle = function(...args){
        const nowTime = new Date().getTime()
        const waitTime = interval - (nowTime - startTime)
        if(waitTime <= 0){
            fn.apply(this,args)
            startTime = nowTime
        }
    }

    return _throttle
}

考虑是否立即执行

function myThrottle(fn, interval, immediate = true){
    let startTime = 0

    const _throttle = function(...args){
        const nowTime = new Date().getTime()
        
        if(!immediate && startTime === 0){
            startTime = nowTime
        }

        const waitTime = interval - (nowTime - startTime)
        if(waitTime <= 0){
            fn.apply(this,args)
            startTime = nowTime
        }
    }

    return _throttle
}

参考:https://blog.csdn.net/m0_71485750/article/details/125581466文章来源地址https://www.toymoban.com/news/detail-765640.html

到了这里,关于JS手写防抖和节流函数(超详细版整理)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 防抖和节流及多种实现方式

    当用户在网页中进行操作时,如点击、滚动、输入等,往往会频繁地触发事件。如果每个事件都立即执行相应的函数,可能会导致性能问题和用户体验不佳,因为这些函数可能需要执行复杂的操作,如计算、网络请求等。 为了优化这种情况,我们可以使用防抖和节流来限制函

    2023年04月24日
    浏览(39)
  • 小程序如何使用防抖和节流?

    防抖(Debounce)和节流(Throttle)都是用来优化函数执行频率的技术,特别在处理用户输入、滚动等频繁触发的情况下,它们可以有效减少函数的执行次数,从而提升性能和用户体验。但它们的工作方式和应用场景有所不同。 防抖的主要思想是,当持续触发事件时,在事件最

    2024年02月13日
    浏览(31)
  • axios、跨域与JSONP、防抖和节流

    Axios 是专注于 网络数据请求 的库。 相比于原生的 XMLHttpRequest 对象,axios 简单易用 。 相比于 jQuery,axios 更加 轻量化 ,只专注于网络数据请求。 axios.get(\\\'url\\\', { params: { /*参数*/ } }).then(callback) 例如: axios.post(\\\'url\\\', { /*参数*/ }).then(callback) 例如: 例如: 如果两个页面的 协议

    2024年02月08日
    浏览(33)
  • Vue - 使用Lodash实现防抖和节流

    GitHub Demo 地址 在线预览 Lodash 官网 更新:对应的vue3版的demo如下: GitHub Demo 地址 在线预览 参考: Vue 防抖节流 详细介绍 vue 优雅的实现防抖和节流 防抖、节流的介绍 js防抖和节流的实现原理及应用场景 js防抖节流应用场景及写法 JS中的防抖 函数节流(throttle)与 函数防抖(

    2024年02月01日
    浏览(40)
  • 防抖和节流 含义及区别图文详解秒懂

    防抖和节流都是为解决短时间内频繁触发某个功能函数而导致的性能问题。比如,触发频率过高而导致响应速度跟不上,以致出现延迟,假死或卡顿的现象。  图解:一件事情,计划5s以后触发,结果中途意外触发了,那么就重新从0开始5秒的计时,这就导致本身计划的事情就

    2024年02月06日
    浏览(32)
  • 了解同源策略 JSONP 案例-淘宝搜索 防抖和节流

    什么是跨域 同源指的是两个 URL 的协议、域名、端口一致,反之,则是跨域。 出现跨域的根本原因:浏览器的同源策略不允许非同源的 URL 之间进行资源的交互。 网页:http://www.test.com/index.html 接口:http://www.api.com/userlist 浏览器对跨域请求的拦截 注意:浏览器允许发起跨域请

    2024年02月05日
    浏览(37)
  • 了解防抖和节流:提升前端交互体验的实用策略

    本文将重点介绍前端性能优化方法之一的防抖和节流。首先解释了它们的概念和原理,然后探讨了它们在前端开发中的应用场景,如输入框搜索、滚动事件等。最后,通过简单的代码示例展示了如何实现防抖和节流函数。通过学习和应用这两种技术,我们可以有效地减少不必

    2024年02月05日
    浏览(35)
  • 前端性能优化的利器 ——— 浅谈JavaScript中的防抖和节流

    防抖和节流函数是工作中两种常用的前端性能优化函数,今天我就来总结一下什么是防抖和节流,并详细说明一下如何在工作中应用防抖和节流函数 在 JavaScript 中,防抖(debounce)和节流(throttle)是用来限制函数执行频率的两种常见技术。 防抖(debounce) 是指在某个时间段

    2024年02月14日
    浏览(46)
  • JS—节流与防抖

    一、js防抖和节流 在进行窗口的resize、scroll、输出框内容校验等操纵的时候,如果事件处理函数调用的频率无限制,会加重浏览器的负担,导致用户体验非常之差。那么为了前端性能的优化也为了用户更好的体验,就可以采用防抖(debounce)和节流(throttle)的方式来到达这种

    2023年04月08日
    浏览(36)
  • 【JS进阶】防抖与节流

    1.防抖 1.1 为什么要防抖? 在项目中,有的操作是 高频触发 的,但是其实触发一次就好了,比如我们短时间内多次缩放页面,那么我们不应该每次缩放都去执行操作,应该只做一次就好。再比如说监听输入框的输入,不应该每次都去触发监听,应该是用户完成一段输入后再进

    2024年02月09日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包