面试官:手写下防抖节流

防抖节流也是曾经被大厂面试过的问题,如果你还不清楚是什么东西,那就赶紧来学习一下吧

防抖

在规定时间内没有第二次操作,才执行(也就是说在规定时间内一直点,就不会执行)

一个很常见的应用场景就是当我们在音乐软件中搜歌的时候,打字打完后停顿时间超过规定时间再去触发搜索。其优点就是可以减少不必要的函数调用,避免不必要的资源消耗

🌰现在我们就以点击按钮为例

xml 复制代码
<body>
	<button id="btn">提交</button>
</body>

我现在就是希望点击提交按钮,控制台能输出一个提交完成,并且规定时间为1s,也就是说这里的防抖就是我在两次点击如果都在1s内是不会打印内容的,只有间隔时间超过1s,我们才能打印,效果给到你

手写如下

xml 复制代码
<body>
    <button id="btn">提交</button>
    <script>
        function send(e){
            console.log(this,'提交完成',e);
        }
        let btn = document.getElementById("btn");
        btn.addEventListener("click", debounce(send,1000))

        function debounce(fn, delay){
            let timer
            return function(){
                    let args = arguments
                    if(timer) clearTimeout(timer);
                    timer = setTimeout(() => {
                        fn.call(this,...args)
                    },delay)
            }
        }
    </script>
</body>
  1. btn.addEventListener("click", debounce(send,1000))事件监听器让括号中的debounce函数this指向了btn,而send函数的this又被call指向了debounce,因此send中this指向了btn。
  2. debounce防抖函数中返回一个函数,这个函数会用到timer这个变量,因此形成一个闭包,使得timer变量在多次调用中保持一致。
  3. 如果timer存在,那么clearTimeout()就掐灭定时器,如果不存在就给它赋值一个定时器,1s后执行send函数,因为send词法环境在全局中,所以要用call改变其指向
  4. 每当你点击一次按钮,都会触发一次debounce函数,第一次点击timer不存在,因此获得一个定时器,1s后执行send函数,第二次点击如果在1s内,那么timer存在,就会掐灭定时器,就这样,执行定时器永远都是在最后一次点击1s后。

节流

在规定时间内,只执行一次。假设我们手速很快很快,但是触发事件的速度是恒速。

一个很常见的应用场景:滚动页面到底部刷新,减少滚动事件触发频率,其优点就是控制函数的调用频率,减轻服务器压力,提高效率,避免过多的计算

🌰还是以点击按钮这个事件,我现在就是手速很快,但是最后触发事件还是只能1s一次,效果如下

手写如下

xml 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button id="btn">搜索</button>

    <script>
        let btn = document.getElementById('btn');
        function send(e){
            console.log('提交了');
        }
        btn.addEventListener('click', throttle(send, 1000))

        function throttle(fn, delay){

            let prevTime = Date.now();
            
            return function(){
                    if(Date.now() - prevTime > delay){
                        // 这里我的arguments没有解构,可以直接用apply,apply接收数组参数
                        fn.apply(this,arguments)
                        prevTime = Date.now()
                    }
            }
        }
    </script>
</body>
</html>

有了防抖的认识,这里节流手写就会方便很多,其核心思想就是两次点击时间差大于delay就开始执行send函数,如果你点击很快,快到两次时间差永远都在delay内,那么随着时间的增加,两次时间差一定会大于delay,因为只有时间差大于delay,prevTime才能更新为当前时间。

Date.now()是当前时间,从1970年开始记录的毫秒,永远都不会相等的值

javascript 复制代码
console.log(Date.now()) // 1700051263045

总结

防抖节流的目的都是为了控制函数执行的频率,但是二者原理不同,防抖是一种延迟策略,即一段连续的触发事件结束后,等待一段时间再去执行;节流是一种控制函数执行频率的策略,一段时间内只执行一次。这两个东西面试容易让你手写代码,建议大家自己多尝试下自己去写函数


如果觉得本文对你有帮助的话,可以给个免费的赞吗[doge] 还有可以给我的gitee链接codeSpace: 记录coding中的点点滴滴 (gitee.com)点一个免费的star吗[星星眼]

相关推荐
Nan_Shu_61416 分钟前
学习: Threejs (2)
前端·javascript·学习
G_G#24 分钟前
纯前端js插件实现同一浏览器控制只允许打开一个标签,处理session变更问题
前端·javascript·浏览器标签页通信·只允许一个标签页
@大迁世界39 分钟前
TypeScript 的本质并非类型,而是信任
开发语言·前端·javascript·typescript·ecmascript
GIS之路1 小时前
GDAL 实现矢量裁剪
前端·python·信息可视化
是一个Bug1 小时前
后端开发者视角的前端开发面试题清单(50道)
前端
Amumu121381 小时前
React面向组件编程
开发语言·前端·javascript
学历真的很重要1 小时前
LangChain V1.0 Context Engineering(上下文工程)详细指南
人工智能·后端·学习·语言模型·面试·职场和发展·langchain
持续升级打怪中1 小时前
Vue3 中虚拟滚动与分页加载的实现原理与实践
前端·性能优化
GIS之路1 小时前
GDAL 实现矢量合并
前端
hxjhnct1 小时前
React useContext的缺陷
前端·react.js·前端框架