防抖函数中clearTimeout的作用及原理(结合事件循环)
防抖中clearTimeout的作用——结合事件循环拆解
先明确测试场景:连续触发5次输入事件(比如快速敲5个字符),调用经过防抖包装的saveInput函数(功能是打印“foo”)。
没有clearTimeout时:为啥会打印5次?
JS是单线程,靠事件循环处理异步任务,setTimeout属于宏任务——它的回调不会立刻执行,而是会被放到宏任务队列里,等当前执行栈的同步代码跑完才会处理。
每次触发输入事件,防抖函数都会执行一遍:
- 第1次触发:创建一个
setTimeout,把saveInput回调扔进宏任务队列,延迟X毫秒执行。 - 第2次触发:又创建一个全新的
setTimeout,再把一个saveInput回调扔进队列。 - 重复到第5次触发,队列里就攒了5个独立的
saveInput回调。
等所有触发事件的同步代码执行完,事件循环会挨个处理这5个宏任务,每个都执行saveInput,自然就打印5次“foo”。
保留clearTimeout时:为啥只打印1次?
防抖函数会维护一个变量(比如timer)存定时器ID,每次触发时先做两件事:
- 调用
clearTimeout(timer):这会直接把上一次触发时创建的、还没执行的定时器从宏任务队列里移除,让它永远没机会运行。 - 再创建新的
setTimeout,把新的ID存在timer里,对应的saveInput回调扔进队列。
所以连续触发5次的过程是:
- 第1次:无旧定时器,直接创建新的。
- 第2次:删掉第1次的定时器,创建新的。
- ...
- 第5次:删掉第4次的定时器,创建新的。
等最后一次触发后,没有新的触发了,这个最后创建的定时器到点后,队列里只有它的saveInput回调,执行一次就只打印1次“foo”。
clearTimeout的核心意义
它就是防抖的“核心阀门”——每次新触发时,把之前还在排队等待执行的延迟任务彻底取消,确保只有最后一次触发的任务能真正执行,从根源上避免了频繁触发导致的目标函数重复执行。
内容的提问来源于stack exchange,提问作者Satyajeet Jha
相关产品推荐
相关产品推荐

