节流与防抖
因为要做一个记忆翻牌配对小游戏,然后在学习时偶然看到“节流”二字,然后就顺便去看了看所谓的“节流”
节流
1.啥是节流
n 秒内只执行一次事件,即使n 秒内事件重复触发,也只有一次生效。
如果这不好理解,那就假设一个场景:
1.你设计了一个表单,这个表单提交的数据内容很多。
2.你的有些用户闲得很无聊,写完表单以后疯狂点击提交按钮。
3.你的后端同事走到你面前指着崩溃的服务器来向你抱怨。
这就像打游戏放技能一样,放完一次技能后就有一段的冷却时间
所以我的第一想法肯定是给这个button一个冷却时间
现在在我面前的有两个东西:一个按钮提交的功能,一个冷却时间,假设为5秒
牵扯到时间会让我第一时间想到 setTimeout和setInterval,首先排除setInterval,因为提交表单这个功能我不希望它循环执行,所以我选择setTimeout。
假设你现在正在玩游戏,游戏有一个技能,它的技能CD是两秒,那么我们就需要判断用户是否在两秒内多处点击了这个技能,如果多次点击,那么无事发生(返回一个空函数),如果不在CD,那么返回这个技能的特效(技能执行的函数)
const fnOnclick = ()=> console.log("技能已经开启!") |
在这里我们需要知道cdTime这个函数只是一个外壳函数,它真正的意义在于传递我们需要的参数,它并不是我们希望onclick真正要执行的函数!cdTime返回的那个函数才是我们真正想执行的函数
现在我们设计cdTime,也就是我们限制 技能 只能在两秒之内释放。
2.代码实现
const fn0nClick = () => console. log("技能已经开启!!") |
然后我在看完节流后又摸过去看了看防抖
防抖
1.啥是防抖
在事件被触发 n 秒后再执行回调,如果在这 n 秒内事件又被触发,则重新计时。
我们拿一个点击按钮来举例子。
function getSearch() { |
现在我们尝试疯狂点击按钮就会疯狂发送请求。
我们现在来修改一下这个函数,我们思考一下🤔,假设我们不借助 debounce 可以实现一个伪防抖的功能吗?答案是百分百可以的。我们先在这个文件下设定一个变量叫做 timerID
let timerId = 0 |
然后我们设定一个定时器,来使这个 console.log(“发请求”) 在 1.5s 后执行。
let timerId = 0 |
然后这里要补充讲一下:setTimeout的返回值
其实 setTimeout 会在 setTimeout 执行的时候返回一个大于 0 的正整数。 所以我们这句话其实是在给 timerID 赋值! 并不是将 setTimeout 函数本身赋值给 timerID 这个变量。
这里我们需要特别搞清楚 setTimout函数本身执行的时候,是马上赋值的,并不是等到 1.5s 后再赋值的。什么意思呢? 我设置了大约在10几年后再执行的一个函数,千万不要觉得 timerID 是会在10年以后才会被赋值。
为什么要这样设计呢?因为如果这样执行的话,就会给我们一个反悔的机会。还说上面的例子。假设我在 5 年后突然反悔不想执行了。我只需要取消这个 timerID 就可以中途放弃执行。
function cancelSearch(){ |
这个 timerID 就是每一个 setTimeout 的身份证。每当你执行一次 setTimout 后,setTimout 所接收的回调函数就会被分配一个唯一 ID,来被放进任务队列。 而 clearTimeout 的功能恰好就是清除位于任务队列里指定的 id 所绑定的那个回调函数。
2.代码实现
let timerId = 0 |