【连载】手摸手解析JS手写面试题题系列1——实现debounce(防抖)方法

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介: 手摸手解析JS手写面试题题系列1——实现debounce(防抖)方法

手摸手解析JS手写面试题题系列1——实现debounce(防抖)方法

关注程序员耳东,编程转码真轻松

这是手摸手解析JS手写面试题系列第1篇,聊聊如何实现debounce(防抖)方法

啥是debounce(防抖)

首先说说啥是debounce, 这个单词中文名就是防抖,之前没接触过的人可能一脸蒙

不过没关系我最擅长的就是通俗易懂的解释清楚概念,我一说你就明白了

举个例子,比如说这样一个场景:

比如下图这样,用户在输入框里面输入字符,然后根据用户输入的字符去后端模糊查询,这是个很常见的场景对吧?这就是经常说到的联想搜索

OK,我们继续探究这个功能的细节

比如你想搜索“世界杯”这三个字,普通的联想输入框是这样运作的:

  1. 在你敲入第一个字的时候,触发了输入框的onchange事件,前端带着“世”这个字向后端发起1次请求
  2. 在你敲入第二个字的时候,触发了输入框的onchange事件,前端带着“世界”这两个字向后端发起1次请求
  3. 在你敲入第三个字的时候,触发了输入框的onchange事件,前端带着“世界杯”这三个字向后端发起1次请求

你品一品,用户飞速的敲完3个字,前端居然发起了3次请求,这合理吗?难道我们不是只需要第3次请求就够了吗?

能不能有一个办法可以让用户停止输入的时候才执行发请求的方法,避免用户在快速输入的时候连续的发请求?

答案就是debounce方法,它可以让某个方法在快速连续被激发的时候不会执行,可以保障用户在输入完毕时才去真正的执行方法

接下来,我们一步一步用代码实现debounce方法

跟我一步一步代码实现debounce(防抖)

写测试的例子

在开始写debounce之前,我们先把验证的代码写好,这样子就可以保证我们写一点代码就可以验证一点代码

记住一点就是,很少有人可以一次性就写出最佳的代码,大部分都是先写个最简单最糙的版本然后一点一点的优化出来的

验证的代码我们就以前面说到的输入框为例,写一个方法来响应input的onChang事件,假装发起了请求,来显示onChang事件的响应频率 测试代码如下:

<body>
    <input id="debounce-input" placeholder="防抖输入框" />
    <script>
        const input = document.getElementById('debounce-input');
        const handleInputOnChange = (e) => {
            console.log(e);
            console.log('发起请求...');
        }

        input.oninput = handleInputOnChange;
    </script>
</body> 

先思考伪代码

我们写一个代码之前呢,先要把它想清楚,只要你想顺了,那代码写的就很顺了,在思考代码逻辑的过程中可以使用伪代码来辅助

什么是伪代码,就是我们使用人话来把我们想要实现的代码过程和步骤讲一遍

OK,思考debounce伪代码之前先看看它是怎么用的

const handleInputOnChangeDebounced = debounce(handleInputOnChange, 300);
input.oninput = handleInputOnChangeDebounced;

这段代码的意思就是我们使用debounce方法把handleInputOnChange方法包装一下,并且返回一个新的方法handleInputOnChangeDebounced

这个handleInputOnChangeDebounced方法响应输入框的输入事件,在用户以非常快的速度(两次输入的间隔时间小于300毫秒)输入的时候,不会去执行handleInputOnChange方法,只有在用户两次输入间隔大于300毫秒才会执行handleInputOnChange方法

这里有个细节需要注意,什么情况下用户两次输入间隔会小于300毫秒,有两种情况:

  1. 用户打字的手速比较慢,两次输入的间隔大于了300毫秒,此时因为用户手速实在是太慢了,我们不需要很刻意的去做debounce,所以每次输入后都会执行一次handleInputOnChange
  2. 用户手速很快的打完了一段文字并且停止了输入,此时最后一次输入完毕后过300毫秒就会执行handleInputOnChange

再开始写代码

OK,我们接下来写代码

首先实现一个最基础的debounce方法的架子:

function debounce(func, wait) {
    return function (...args) {
        // 代码
    }
}

debounce方法接收两个参数func和wait,func是被包装的方法,wait是用户两次输入间隔大于多少时会执行func

接下来问题的难点就是如何实现:用户两次输入间隔大于wait时才执行func,否则就不执行func

这个问题其实可以从这个角度来思考:

我们可以借助定时器setTimeout来做,声明一个定时器来在wait时间后执行func

如果用户输入的很慢(两次输入间隔大于了wait)或者输入结束,那这个setTimeout就顺利了执行了func;

如果用户输入的很快(两次输入间隔小于了wait),那我们取消当前这个setTimeout再重新生成一个新的setTimeout去延时执行func即可;

这样子我们就巧妙的使用了定时器的延时来控制函数的响应,延时范围内的就新生成一个定时器,延时范围外的就让它执行好了,也该它执行了

代码如下:

function debounce(func, wait) {
    let timerId = 0;
    return function (...args) {
        if (timerId) {
            clearTimeout(timerId);
        }
        timerId = setTimeout(() => {
            func.apply(this, args);
        }, wait);
    }
}

这里面的细节我说一下,防止有的人看不太明白

变量timerId放在返回的方法外面,用来记录当前的那个定时器,并且timerId会在返回的方法内部使用到,这不就是妥妥的闭包吗?之前学习到的知识瞬间就用到了

然后返回的方法内部有一个if判断,就是如果当前有个定时器,别管这个定时器是否执行,先取消了再说,因为如果它执行了,那我clear它也不会有什么影响,如果它没执行,那刚好说明它还在wait这个时间间隔内,正好取消掉它

取消掉当前的定时器之后,再新生成一个定时器来延时执行func

定时器内部执行func的时候,需要把方法接收的参数都透传给func,并要保留住this

验证

验证代码就很简单了,如下:

<body>
    <input id="debounce-input" placeholder="防抖输入框" />
    <script>
        const input = document.getElementById('debounce-input');
        const handleInputOnChange = (e) => {
            console.log('发起请求...');
        }

        input.oninput = debounce(handleInputOnChange, 300);
    </script>
</body>

总结

这是手摸手解析JS手写面试题的第1篇,实现debounce方法是一个非常常见并且非常锻炼javascript能力的过程,在这个过程中练习到了闭包、定时器、抽象思维等等能力

希望对你们有帮助,有问题欢迎讨论

相关文章
|
1月前
|
JavaScript 前端开发 程序员
前端原生Js批量修改页面元素属性的2个方法
原生 Js 的 getElementsByClassName 和 querySelectorAll 都能获取批量的页面元素,但是它们之间有些细微的差别,稍不注意,就很容易弄错!
|
1月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
76 2
|
1月前
|
Web App开发 JavaScript 前端开发
如何确保 Math 对象的方法在不同的 JavaScript 环境中具有一致的精度?
【10月更文挑战第29天】通过遵循标准和最佳实践、采用固定精度计算、进行全面的测试与验证、避免隐式类型转换以及持续关注和更新等方法,可以在很大程度上确保Math对象的方法在不同的JavaScript环境中具有一致的精度,从而提高代码的可靠性和可移植性。
|
1月前
|
监控 JavaScript Java
Node.js中内存泄漏的检测方法
检测内存泄漏需要综合运用多种方法,并结合实际的应用场景和代码特点进行分析。及时发现和解决内存泄漏问题,可以提高应用的稳定性和性能,避免潜在的风险和故障。同时,不断学习和掌握内存管理的知识,也是有效预防内存泄漏的重要途径。
127 52
|
1月前
|
JavaScript 前端开发 索引
js中DOM的基础方法
【10月更文挑战第31天】这些DOM基础方法是操作网页文档结构和实现交互效果的重要工具,通过它们可以动态地改变页面的内容、样式和行为,为用户提供丰富的交互体验。
|
1月前
|
缓存 JavaScript UED
js中BOM中的方法
【10月更文挑战第31天】
|
20天前
|
Java 程序员
面试官的加分题:super关键字全解析,轻松应对!
小米,29岁程序员,通过一个关于Animal和Dog类的故事,详细解析了Java中super关键字的多种用法,包括调用父类构造方法、访问父类成员变量及调用父类方法,帮助读者更好地理解和应用super,应对面试挑战。
35 3
|
1月前
|
JSON JavaScript 前端开发
[JS]面试官:你的简历上写着熟悉jsonp,那你说说它的底层逻辑是怎样的?
本文介绍了JSONP的工作原理及其在解决跨域请求中的应用。首先解释了同源策略的概念,然后通过多个示例详细阐述了JSONP如何通过动态解释服务端返回的JavaScript脚本来实现跨域数据交互。文章还探讨了使用jQuery的`$.ajax`方法封装JSONP请求的方式,并提供了具体的代码示例。最后,通过一个更复杂的示例展示了如何处理JSON格式的响应数据。
38 2
[JS]面试官:你的简历上写着熟悉jsonp,那你说说它的底层逻辑是怎样的?
|
1月前
|
缓存 JavaScript 前端开发
JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用
本文深入讲解了 JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用。
45 5
|
1月前
|
JavaScript 前端开发
js中的bind,call,apply方法的区别以及用法
JavaScript中,`bind`、`call`和`apply`均可改变函数的`this`指向并传递参数。其中,`bind`返回一个新函数,不立即执行;`call`和`apply`则立即执行,且`apply`的参数以数组形式传递。三者在改变`this`指向及传参上功能相似,但在执行时机和参数传递方式上有所区别。
27 1

推荐镜像

更多