js防抖具体实现以及详细原理步骤说明(附实例)

目录
  • Why?为啥要有防抖?
  • What? 啥是防抖?
  • How? 防抖咋用啊?
  • 什么是延迟debounce??
  • 总结

ps:本文将从一个案例出发循序渐进,在其中你不仅能知道防抖是如何实现的,还可以学习到关于 this 、apply、arguments 等知识的具体应用。

Why?为啥要有防抖?

因为有时候频繁的事件触发是没有意义的,不仅影响性能还可能造成卡顿。

为了避免这种情况,我们需要用防抖来解决这个问题。

What? 啥是防抖?

防抖debounce:

简单来说,防抖的效果就是在一定的时间间隔内,多次触发只有一次触发产生

How? 防抖咋用啊?

首先先从一个实例入手:

我们设置一个按钮用来切换上方文本的颜色,如下:

    <h2 id="demo">hello</h2>
    <button id="btn">点我</button>

    <script type="text/javascript">
        var btn = document.getElementById('btn');

        btn.addEventListener('click', changeColor, false);

        var flag = true
        function changeColor() {
            if (flag) {
                document.getElementById('demo').style.color = 'pink'
            } else {
                document.getElementById('demo').style.color = 'blue'
            }
            flag = !flag
        }

如果你想要让用户在1秒内不能频繁切换 ,即1秒内只能给文本换一种颜色。

那么你可以利用定时器来实现,不过直接写一个定时器是不够的,因为你只能实现多次触发延时执行,而不是限制触发。

你可以使用一个变量来判断你的每次按下按钮时候是否已经触发过定时器了,如果触发过了就将原来触发但还没到1秒的定时器清除,接着重新来个1秒的定时器;如果没触发过说明你1秒内没按过,新建一个1秒的定时器就行。

这样就可以保证防抖的效果实现了,请看代码:

    <h2 id="demo">hello</h2>
    <button id="btn">点我</button>

    <script type="text/javascript">
        var btn = document.getElementById('btn');

        btn.addEventListener('click', debounce(changeColor), false);

        var flag = true
        function changeColor() {
            if (flag) {
                document.getElementById('demo').style.color = 'pink'
            } else {
                document.getElementById('demo').style.color = 'blue'
            }
            flag = !flag
        }

        function debounce(fn) {
            let t = null
            return function () {
                //如果定时器存在就清除掉
                if (t) {
                    clearTimeout(t)
                }
                //不然就创建新的定时器
                t = setTimeout(function() {
                    fn()
                }, 1000)
            }
        }
</script>

看完代码你可能会有如下疑惑:

1. 怎么这个debounce函数里面不能直接写执行内容吗?非要return一个函数?

解:因为你已经把changeColor函数当成参数传给debounce函数了(看下面的代码变化),你要在btn上绑定debounce事件就要在debounce里面将改造好的changeColor事件写成一个回调函数。

// btn.addEventListener('click', changeColor, false);
btn.addEventListener('click', debounce(changeColor), false);

2. 这个 let t = null; 岂不是会每次都将 t 置为 null ??这可咋实现呢?

 解:你以为 btn 绑定的是 debounce,所以你认为每次触发都会执行 t = null。

漏! btn 绑定的是debounce(changeColor)!这个括号不可忽视,实际上每次触发click事件执行的是它的回调,也就是 return 里面的内容,let t = null 只会在初始化的时候执行一次。

虽然目前已经实现了防抖的效果,但是这么写的话,你会发现changeColor函数是拿不到事件对象的,也就是说它拿不到本该属于它的 event 。

要想让它拿回本该属于它的 event ,你可以这么做:

1.基于当前 event 已经在 debounce 上了,你可以将 e 当参数传递给 debounce 里回调的函数

2.再把e传给回调函数中定时器里的 fn() ,即 fn(e)

function debounce(fn) {
            let t = null
            //往这里传e
            return function (e) {
                if (t) {
                    clearTimeout(t)
                }

                t = setTimeout(function() {
                    //再带给fn
                    fn(e)
                }, 1000)
            }
        }

届时,你就会发现 changeColor 它拿到了事件对象!

如果你问,非要拿这个e干啥呢??

那么我只能说,拿到了e可以对e做一些操作(像是e.target可以更改等等),如果你不对e做什么不传给它也没关系,只是这么写可以离一个完美的防抖函数更近而已。

但是你不能保证只有一个参数需要传给 changeColor ,所以在传参的时候只写一个 e 没办法实现多个参数的传递,那么为了更完美一点,我们接着来改改。

说到多个参数的传递你大概会想到实参列表 arguments 。没错!就是它!

如果你不了解 arguments,请前往:学arguments去喽

arguments对象是所有(非箭头)函数中都可用的局部变量。你可以使用arguments对象在函数中引用函数的参数。此对象包含传递给函数的每个参数,第一个参数在索引0处

首先,我们试着用 arguments[0] 去代替刚刚传递的 e ,你会发现:

那个return里的 arguments[0] 根本传不到定时器里,那就更别提传到 changeColor 了。

因为每个函数里的 arguments 都是自己函数内部的,定时器里的函数没有 arguments 所以 undefined。

要解决这个问题的话,你可以使用赋值的方式把 arguments 存下来,还可以使用箭头函数。

接下来采用箭头函数的方式来解决:

因为箭头函数内部没有 arguments 对象,它会往外找,这样就可以得到 return 里的 arguments。

function debounce(fn) {
            let t = null
            return function () {
                console.log('我是回调的arguments',arguments[0]);
                if (t) {
                    clearTimeout(t)
                }

                //这里用箭头函数
                t = setTimeout(() => {
                    fn(arguments[0])
                    console.log('我是定时器里的arguments', arguments[0])
                    // console.log(this)
                }, 1000)
            }
        }

这样子就实现了 arguments[0] 的传递问题,如果是多个参数的话可以使用 apply 方法 将整个 arguments 作为参数传递过去,如下:

function debounce(fn) {
            let t = null
            return function () {
                if (t) {
                    clearTimeout(t)
                }

                t = setTimeout(() => {
                    fn.apply(this, arguments)
                }, 1000)
            }
        }

其中,apply方法的第一个参数还可以将 changeColor 的 this 由 Window 转为 btn,属于是一个一举两得的大动作了。 (因为箭头函数会往外找this继承,所以拿到了return里的this再传给changeColor)

如果你不了解apply,请前往:学apply去喽

写到这里,一个 延迟debounce 就诞生了!

什么是延迟debounce??

顾名思义,在延迟结束那一刻才触发回调。

如果你觉得每次按完按钮还要等等才能改颜色真是太烦了,估计没等到改颜色你就关闭网页了。

前缘debounce 可以解决这个问题!(即在定时器开始的那一刻就触发事件)

将代码再改一改你就可以得到 前缘debounce 啦!

function debounce(fn) {
            let t = null
            return function () {
                // 用firstClick来记录每一次定时器开始的第一次按下的动作
                var firstClick = !t

                if(t) {
                    clearTimeout(t)
                }

                if(firstClick) {
                    fn.apply(this, arguments)
                }

                //等待1秒后将 t 置为 null,在这1秒内如果再点击事件就会去到if(t)的执行
                t = setTimeout(() => {
                    t = null
                }, 1000)
            }
        }

这个前缘debounce将会实现每次连续点击后先响应一次事件,再去等1秒。

总结

到此这篇关于js防抖具体实现以及详细原理步骤的文章就介绍到这了,更多相关js防抖实现内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • JS中的防抖与节流及作用详解

    概念 函数防抖(debounce)是指在一定时间内,在动作被连续频繁触发的情况下,动作只会被执行一次,也就是说当调用动作过n毫秒后,才会执行该动作,若在这n毫秒内又调用此动作则将重新计算执行时间,所以短时间内的连续动作永远只会触发一次,比如说用手指一直按住一个弹簧,它将不会弹起直到你松手为止. 函数节流是指一定时间内执行的操作只执行一次,也就是说即预先设定一个执行周期,当调用动作的时刻大于等于执行周期则执行该动作,然后进入下一个新周期,一个比较形象的例子是如果将水龙头拧紧直到水是以水滴的形式流出

  • JS函数节流和函数防抖问题分析

    问题1:如果实现了dom拖拽功能,但是在绑定拖拽事件的时候发现每当元素稍微移动一点便触发了大量的回调函数,导致浏览器直接卡死,这个时候怎么办? **问题2:**如果给一个按钮绑定了表单提交的post事件,但是用户有些时候在网络情况极差的情况下多次点击按钮造成表单重复提交,如何防止多次提交的发生? 为了应对如上场景,便出现了 函数防抖 和 函数节流 两个概念,总的来说: 这两个方法是在 时间轴上控制函数的执行次数. 函数防抖(debounce) 概念: 在事件被触发n秒后再执行回调,如果在这n秒内

  • js防抖和节流的深入讲解

    前言: 我们在做页面事件绑定的时候,经常要进行节流处理,比如鼠标异步点击,去执行一个异步请求时,需要让它在上一次没执行时不能再点击,又或者绑定滚动事件,这种持续触发进行dom判断的时候,就要按一定频率的执行. 本文主要给大家介绍了关于js防抖和节流的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧 0. 引入 首先举一个例子: 模拟在输入框输入后做ajax查询请求,没有加入防抖和节流的效果,这里附上完整可执行代码: <!DOCTYPE html> <html la

  • javascript防抖函数debounce详解

    定义及解读 防抖函数 debounce 指的是某个函数在某段时间内,无论触发了多少次回调,都只执行最后一次.假如我们设置了一个等待时间 3 秒的函数,在这 3 秒内如果遇到函数调用请求就重新计时 3 秒,直至新的 3 秒内没有函数调用请求,此时执行函数,不然就以此类推重新计时. 举一个小例子:假定在做公交车时,司机需等待最后一个人进入后再关门,每次新进一个人,司机就会把计时器清零并重新开始计时,重新等待 1 分钟再关门,如果后续 1 分钟内都没有乘客上车,司机会认为乘客都上来了,将关门发车. 此

  • 如何解决js函数防抖、节流出现的问题

    React中使用防抖函数和节流函数 在React事件调用时,React传递给事件处理程序是一个合成事件对象的实例.SyntheticEvent对象是通过合并得到的. 这意味着在事件回调被调用后,SyntheticEvent 对象将被重用并且所有属性都将被取消. 这是出于性能原因. 因此,您无法以异步方式访问该事件.React合成事件官方文档 所以在用防抖或节流函数封装时,异步方式访问事件对象出现问题.解决的方法如下: 方法一:调用合成事件对象的persist()方法 event.persist

  • 通过实例讲解JS如何防抖动

    前言 这道题目经常与事件触发器同时存在,为了考察面试者在一些具体业务流程上(信息流,搜索框输入查询)等,能否综合的考虑实现思路. 题目 在某些信息列表中一般采用瀑布流,滚动一屏时加载相应的数据,请思考如何避免连续下拉时而产生的问题(可能是页面崩溃,也可能是巨卡无比). 一般情况下,如果碰到这样的面试题,防抖动机制,就能很好的解决,这方面最早的应用实践还是Twitter,开发者写了一篇博客,详细的阐述了如何解决这样的问题.那么,说到防抖动,其核心内涵在于延迟处理,也就是将一系列的事件处理程序全部延

  • JavaScript函数节流和函数防抖之间的区别

    一.概念解释 函数节流和函数防抖,两者都是优化高频率执行js代码的一种手段. 大家大概都知道旧款电视机的工作原理,就是一行行得扫描出色彩到屏幕上,然后组成一张张图片.由于肉眼只能分辨出一定频率的变化,当高频率的扫描,人类是感觉不出来的.反而形成一种视觉效果,就是一张图.就像高速旋转的风扇,你看不到扇叶,只看到了一个圆一样. 同理,可以类推到js代码.在一定时间内,代码执行的次数不一定要非常多.达到一定频率就足够了.因为跑得越多,带来的效果也是一样.倒不如,把js代码的执行次数控制在合理的范围.既

  • JS函数节流和防抖之间的区分和实现详解

    在写JS时,这两个函数比较常见,有时候傻傻分不清用哪个,或者说知道代码要怎么写,但要说出它究竟是节流函数还是防抖函数时一脸楞逼.今天有一个同学分享了这两个的区分,我也来回顾一下,加深一下印象,以便日后用到时心里有底.PS:百度和谷歌搜索前几个介绍都是相反介绍,本文为原创,如有雷同纯属抄袭我的. 节流概念(Throttle) 按照设定的时间固定执行一次函数,比如200ms一次.注意:固定就是你在mousemove过程中,执行这个节流函数,它一定是200ms(你设定的定时器延迟时间)内执行一次.没到

  • js防抖具体实现以及详细原理步骤说明(附实例)

    目录 Why?为啥要有防抖? What? 啥是防抖? How? 防抖咋用啊? 什么是延迟debounce?? 总结 ps:本文将从一个案例出发循序渐进,在其中你不仅能知道防抖是如何实现的,还可以学习到关于 this .apply.arguments 等知识的具体应用. Why?为啥要有防抖? 因为有时候频繁的事件触发是没有意义的,不仅影响性能还可能造成卡顿. 为了避免这种情况,我们需要用防抖来解决这个问题. What? 啥是防抖? 防抖debounce: 简单来说,防抖的效果就是在一定的时间间隔

  • 详细聊一聊js防抖节流到底是什么

    目录 前言 场景 防抖 核心 解释 修复场景例子 节流 核心 解释 修复场景例子 总结 前言 防抖和节流,这是前端防止用户频繁调用同一个接口的方法,比如短时间重复点击上传同一个文件,短时间重复点击提交同一个评论,异步的操作还没给你带来反馈,于是你重复上传了多个文件,重复提交了多个评论. 本文以常见的使用场景与解决方案,一篇教会你如何使用防抖节流. 场景 为了例子更加简单,我们就用延迟来模拟一个后端接口返回的过程. <body> <button onclick="comment(

  • 基于JS对象创建常用方式及原理分析

    前言 俗话说"在js语言中,一切都对象",而且创建对象的方式也有很多种,所以今天我们做一下梳理 最简单的方式 JavaScript创建对象最简单的方式是:对象字面量形式或使用Object构造函数 对象字面量形式 var person = new Object(); person.name = "jack"; person.sayName = function () { alert(this.name) } 使用Object构造函数 var person = { na

  • 使用Node.js搭建静态资源服务详细教程

    对于Node.js新手,搭建一个静态资源服务器是个不错的锻炼,从最简单的返回文件或错误开始,渐进增强,还可以逐步加深对http的理解.那就开始吧,让我们的双手沾满网络请求! Note: 当然在项目中如果有使用express框架,用express.static一行代码就可以达到目的了: app.use(express.static('public')) 这里我们要实现的正是express.static背后所做工作的一部分,建议同步阅读该模块源码. 基本功能 不急着写下第一行代码,而是先梳理一下就基

  • Qt 实现钢笔画线效果示例及详细原理

    前言 上一篇文章:Qt 实现画线笔锋效果详细原理,根据这篇介绍的实现笔锋效果的原理,我们很容易实现另外一种笔效:钢笔. 所谓的钢笔笔效,就是真实还原钢笔书写出来的线条效果,其特征就是:根据笔的绘制速度而线条的宽度会逐渐变化,写得越快,线条越细,并且在收笔时带有笔锋效果. 那么,在上一篇文章的基础上,稍微修改一下,就可以实现这个效果,看下效果图: 实现原理 从上一篇文章我们知道,绘制的曲线是通过每两个点形成一条贝塞尔曲线,所以在不松手的情况下连续画线,整条线段是包含很多条path组合而成的.而要实

  • Qt 实现画线笔锋效果详细原理及示例代码

    前言 之前写过一篇文章介绍Qt中绘制平滑曲线的两种方式,文章在这里.这篇文章详细介绍了绘制的原理和实现方式,那么,如果要在此曲线上实现笔锋效果怎么做呢? 所谓的笔锋效果,就是钢笔书写抬笔时的笔尖,也就是说,绘制曲线抬笔时形成一个笔尖的效果. 话不多说,直接来看效果: 动画效果如下: 实现原理 要实现该效果,需要完成以下几个关键步骤: 1.每两个点形成一个贝塞尔曲线path进行绘制 2.最新的一条path绘制细线(笔锋最细处的宽度) 3.倒数第二条path绘制粗线(正常的线条宽度) 4.在两条pa

  • js防抖函数和节流函数使用场景和实现区别示例分析

    本文实例讲述了js防抖函数和节流函数使用场景和实现区别.分享给大家供大家参考,具体如下: 开发过程中,都遇到过某个事件被频发触发的场景,比如resize,scroll事件,input事件,而对应的事件处理函数也会被高频率调用,这时会增加浏览器负担,用户体验也不好,这也是防抖函数和节流函数存在的意义和使用场景. 函数防抖(debounce): 持续触发事件时,在设定时间段内没有被触发,才去调用事件处理函数,在设定时间段内如果事件又被触发,则不调用事件处理函数,并从触发事件时间重新开始延时. 具体实

  • JS防抖节流函数的实现与使用场景

    目录 一.什么是函数防抖 1.为什么需要函数防抖? 2.函数防抖的要点 3.函数防抖的实现 4.函数防抖的使用场景 二.什么是函数节流 1.函数节流的要点 2.函数节流的实现 3.函数节流的使用场景 总结 一.什么是函数防抖 概念:函数防抖(debounce),就是指触发事件后,在 n 秒内函数只能执行一次,如果触发事件后在 n 秒内又触发了事件,则会重新计算函数延执行时间. 1.为什么需要函数防抖? 前端开发过程中,有一些事件,常见的例如,onresize,scroll,mousemove ,

  • window10系统下nvm详细安装步骤以及使用

    目录 前言 win10 nvm安装及使用 总结 前言 nvm是一个管理nodejs版本的工具.在实际的开发中,有些项目的开发依赖需要低版本的nodejs运行环境,此时我们就需要使用nvm来降低nodejs版本. win10 nvm安装及使用 1.下载安装nvm,首先安装目录不要有空格和中文,会出现乱码 下载地址: https://github.com/coreybutler/nvm-windows/releases 2.解压之后安装,安装路径默认的是C盘,如果C盘内存不够的话可以安装到D盘,一般

随机推荐