小编认为的比较有意义的延伸面试点考察
为什么使用节流的方式去处理消息发送事件
使用节流的方式来处理消息发送和按钮提交时间,主要是为了在一定时间内限制执行频率,防止短时间内的重复触发。虽然防抖也可以控制频率,但节流在这些情况下更适合。
- 防止频繁提交、发送,且允许固定时间间隔内执行。
- 在消息发动或按钮提交的场景中,通常希望短时间内只允许用户点击一次,例如每隔1s或2s。节流可以确保在设定的间隔内执行一次,而防抖在这个场景下会导致执行时间不确定。
- 使用节流可以让用户在每个固定间隔后再次触发事件,例如每秒发送一次消息,用户不需要等待太长的延迟。防抖则需要用户停止点击,等待延迟时间到达后才会触发,这对用户体验会有影响。
- 节流避免延迟执行带来的响应不及时
- 防抖在用户频繁操作时会不断重置计时器,只有在用户完全停止操作的情况下才会触发一次。而消息发送和表单提交通常希望在每次点击时都执行操作,只是限制频率而已。
- 例如:在聊天场景中,如果用户多次点击“发送”按钮,使用防抖会让消息发送变得不确定,用户可能需要等待操作完成,影响即时性。使用节流则可以确保在设定的间隔内最多触发一次发送,而不需要等待额外的延迟。
- 节流适合限制操作频率而不影响正常使用
- 在用户需要连续操作但又希望限制操作频率的情况下,节流更合适,因为它允许用户每隔一段时间就可以触发一次。而防抖则会导致在频繁操作时没有任何触发结果。
- 按钮提交和消息发送场景中,用户通常会希望即时收到响应(如发送成功的反馈),而不是等待延迟。节流在频率控制的同时不会打断操作的连续性,符合这类场景的需求。
小总结
在消息发送和按钮提交等场景中,节流可以通过固定时间间隔触发,防止短时间内多次触发,同时让用户体验到即时响应。而防抖在这里则容易导致延迟和响应不确定,不适合这些场景。所以,节流更适合在需要限制频率但不影响响应即时性的场景中使用。
在两者互相嵌套的情况下,会有什么问题
将debounce包在throttle内部
这种组合方式可以确保函数在固定时间间隔内触发,但在用户停止操作时不会再额外的触发调用。具体来说,throttle会限制频率,而debounce在throttle触发时进行最后一次延迟调用。
-
执行效果
const throttledDebouncedFunc = _.throttle(_.debounce(func, 1000), 5000);- 外层
_.throttle:确保func最多每5000ms触发一次 - 内部
_.debounce:确保在1000ms毫秒无操作时才调用func,即每次throttle触发时,debounce会先延迟执行。
- 外层
-
这样组合效果是:
-
每 5000ms 内最多触发一次,并且这次触发还需要满足
debounce的延迟条件。 -
即使在频繁操作时,
func也会在指定的throttle间隔后触发。 -
当用户停止操作 1000ms 后,func 会通过
debounce的延迟被调用。
-
-
适用场景:适合需要频率控制但希望一定延迟后再执行的场景。
-
延迟加载内容: 滚动条快速滚动时,不想频繁请求加载数据,但希望在每次间隔结束后等待一段时间来确认操作是否停止。
-
避免频繁操作触发敏感操作: 比如间隔时间内有大量操作时,
throttle控制频率,而debounce则确保触发事件有延迟,避免过早执行操作。
-
将throttle包在debounce内部
这种方式呢,会在频繁调用之后全部被防抖掉。这里会分为两种情况:
-
如果节流的延迟时间小于防抖时间,
throttle将不会再起作用,所以小编认为这种方式没有意义。 -
如果节流的延迟时间大于防抖时间,
throttle将会频率限制保存。比如1s的防抖你可以触发三次保存,但是3s的节流可以限制你保存1次。
小总结
debounce在throttle内部:确保在触发频率内有延迟,且在频率外等待操作停止后执行。适合延迟执行的节流场景。throttle在debounce内部:用于高频事件中,在频繁操作后保证最终触发,适合在操作结束时执行一次的场景。而这种方式呢,可以只使用debounce。
防抖(Debounce)与节流(Throttle)的定义
- 防抖(Debounce): 一种在事件被频繁触发的情况下,确保事件处理函数只会在最后一次触发后的一段延迟时间才执行。
- 例子:用户输入搜索框时不断触发搜索请求,通过防抖可以请求只在用户停止输入后执行。
- 节流(Throttle): 一种在事件被频繁触发的情况下,确保事件处理函数在设定的时间间隔内最多只会执行一次。
- 例子:监听滚动事件时可以使用节流,避免页面频繁计算或重新渲染。
使用场景分析
- 防抖的常见使用场景:
- 搜索框输入:减少请求次数,避免频繁请求接口。
- 调整窗口大小:页面元素布局调整只在窗口调整完毕后触发。
- 表单校验:实时校验表单输入内容,减少计算频率。
- 节流的常见使用场景:
- 滚动加载:避免滚动事件频繁触发请求。
- 页面元素拖拽:控制拖拽事件触发频率,提高性能。
- 按钮点击:防止用户频繁点击触发多次操作。
防抖(Debounce)实现方式
-
实现思路: 每次事件触发时,清除前一个计时器,重新设置计时器。
-
代码实现
function debounce(func, delay) { let timer = ""; return function(...args) { // 清除前一个定时器 clearTimeout(timer); // 设置新的定时器 timer = setTimeout(() => { func.apply(this, args); }, delay) } } -
详解:
timer:用于存储当前的计时器。clearTimeout:每次时间触发时清除上一次的计时器,确保只在最后一次触发后执行。setTimeout:在设定的延迟时间后执行传入的函数。
节流(Throttle)实现方式
-
实现思路: 记录上次触发事件的时间,与当前时间比较,如果时间差大于设定的间隔则执行。
-
代码实现:
function throttle(func, delay) { let lastTime = 0; return function(...args) { const now = new Date().getTime(); if(now - lastTime >= delay){ lastTime = now; func.apply(this, args); } } } -
详解:
lastTime:记录上一次执行的时间。Date.now():获取当前时间,计算时间差,判断是否满足时间间隔。func.apply:条件满足时,执行传入的函数。
市面使用量居多的 lodash 中的防抖和节流方法
- Lodash: Lodash是一个JavaScript工具库,其中提供了
_.debounce和_.throttle方法,适用于防抖和节流。 - 使用方式:
_.debounce(func, wait, [options])_.throttle(func, wait, [options])
尤其注意,options 中的参数可能会导致输出结构会与想象中有些差别,比如节流的参数可能会导致最终执行完成之后再次触发。
防抖和节流的优缺点
- 防抖的优缺点
- 优点:确保只执行一次,避免频繁操作。
- 缺点:用户可能需要等待延迟结束才可以看到反馈,不适用于需要即时反馈的情况。
- 节流的优缺点:
- 优点:通过控制频率降低开销,适合高频率触发的事件。
- 缺点:不够精准,可能导致用户在等待间隔期间无法得到即时反馈。
综合应用场景
-
表单自动保存功能
-
案例描述
在表单中进行输入时,为了避免用户每次输入都触发保存操作,使用节流和防抖组合的方式来控制频率。在用户输入时,每隔一段时间保存一次,输入停止后延迟一段时间再做一次最终保存。
-
代码示例
const saveData = (data) => { console.log("自动保存数据:", data); } // 先使用节流,确保每5s最多触发一次 const throttledSave = _.throttle(saveData, 5000); // 然后使用防抖,确保用户停止输入1s后触发最终保存 const saveDataWithDebAndThr = _.debounce(throttledSave, 1000) // 监听输入框的输入事件 document.querySelector('#input').addEventListener('input', (event) => { const {value} = event.target; saveDataWithDebAndThr(value) })
-
-
滚动事件监听与加载新的内容
-
案例描述
在长页面中使用无限滚动加载内容时,可以通过节流限制滚动事件触发频率,避免频繁请求新内容。同时在用户停止滚动时使用防抖,确保滚动结束后再次触发检查加载。
-
代码示例
const loadMore = () => { console.log("加载更多内容...") } // 滚动过程中的节流,限制每500ms检查一次 const throttled = _.throttle(loadMore, 500); // 滚动停止之后的防抖,确保停止300ms后再次检查 const throttled = _.debounce(loadMore, 300); // 监听滚动事件 window.addEventListener('scroll', () => { throttled(); throttled(); });
-
-
表单字段实时校验与提交按钮控制
-
案例描述
在表单对每个字段进行实时校验,通过防抖来控制检验频率,避免每次输入都触发校验逻辑。同时对提交按钮进行节流,确保短时间内不会多次触发提交。
-
代码示例
const validData = (input) => { console.log('校验输入:', input); } // 防抖校验输入字段, 用户停止输入 300ms 后触发 const debouncedValid = _.debounce(validData, 300); const submitForm = () => { console.log("提交表单"); } // 提交按钮的节流,限制每隔2s最多提交一次 const throttledSubmit = _.throttle(submitForm, 2000); // 监听输入框的输入事件 document.querySelector('#inputField').addEventListener('input', (event) => { const {value} = event.target; debouncedValid(value) }) // 监听提交按钮点击事件 document.querySelector("#submitBtn").addEventListener('click', submitForm)
-
-
窗口调整时的图表重绘
-
案例描述
在窗口调整大小过程中,可以通过节流来控制图表重绘频率,防止频繁触发消耗性能。同时在调整结束之后使用防抖进行最终一次的精准重绘。
-
代码示例
const resizeChart = () => { console.log("重绘图表"); } // 窗口调整时的节流,每 500ms 重绘一次图表 const throttledResize = _.throttle(resizeChart, 500) // 窗口调整结束后的防抖,确保调整停止 200 ms 后进行最终重绘 const debouncedResize = _.debounce(resizeChart, 200) // 监听窗口调整事件 window.addEventListener('resize', () => { throttledResize() debouncedResize() })
-
-
实时聊天中的消息发送按钮
-
案例描述
在实时聊天场景中,避免用户快速点击发送按钮导致重复消息。使用节流来限制点击的频率,每隔一段时间才能发送一条消息。
-
代码示例
const sendMessage = () => { console.log("发送消息"); } // 使用节流限制每1s最多发送一次消息 const throttledSend = _.throttle(sendMessage, 1000); // 监听发送消息按钮点击事件 document.querySelector('#sendButton').addEventListener('click', throttledSend)
-