再也不怕面试官问我防抖与节流了

开发 后端
防抖就是要延迟执行,你一直操作触发事件一直不执行,当你停止操作等待多少秒后才执行,节流顾名思义,一节一节的流,就好似控制水阀,在事件不断触发的过程中,固定时间内执行一次事件。

最近去面试,又遇到面试官问我防抖与节流了,而明明前几天就看过手写代码,却写不出来。有时候我在想,是不是自己太笨了。

回归正题

防抖

先不说概念,按自己的理解,在单反里,有防抖机制。因为人在拿着单反的时候会手抖(单反重),按下快门的瞬间,照片会糊,所以有防抖机制,以防止新手把照片拍糊。

单反中的防抖是防止抖动,让人拍出清晰的照片,JavaScript 中的防抖是为了什么?

同理,它的作用也是防止抖动。试想当你频繁触发一个事件时,就会引起不必要的性能损失,那么让该事件在停止触发后再触发,以此减少部分性能。

防抖的定义

防抖就是要延迟执行,你一直操作触发事件一直不执行,当你停止操作等待多少秒后才执行。

也就是说不管事件触发频率有多高,一定在事件触发 n 秒后执行。如果在事件触发的 n 秒又触发了这个事件,那就以新事件的事件为准,n 秒后才执行。总之,要等你触发完事件 n 秒内不再触发事件,它才执行。

手写防抖

根据定义,我们知道要在时间 n 秒后执行,那么我们就用定时器来实现:

function debounce(event, wait) {
let timer = null;
return function (...args) {
clearTimeout(timer); // 清除setTimeout,使其回调函数不执行
timer = setTimeout(() => {
event.apply(this, args)
}, wait)
}
}

代码很简单,即当还在触发事件时,就清除 timer,使其在 n 秒后执行,但此写法首次不会立即执行,为其健壮性,需加上判断是否第一次执行的第三个参数 flag,判断其是否立即执行。

function debounce(event, wait, flag) {
let timer = null;
return function (...args) {
clearTimeout(timer)
if (!timer && flag) {
event.apply(this, args)
} else {
timer = setTimeout(() => {
event.apply(this, args)
}, wait)
}
}
}

防抖场景

窗口大小变化,调整样式

window.addEventListener('resize', debounce(handleResize, 200))

搜索框,输入后1000毫秒搜索

debounce(fetchSelectData, 300)

表单验证,输入 1000 毫秒后验证

debounce(validator, 1000)

防抖帝王库

两大工具库都有防抖源码,可供参考:

  • lodash-debounce。
  • underscore-debounce。

节流

顾名思义,一节一节的流,就好似控制水阀,在事件不断触发的过程中,固定时间内执行一次事件。

手写节流

因为是固定时间内执行一次时间,所以我们有两种实现方法,一用时间戳,二用定时器。

时间戳

function throttle(event, wait) {
let pre = 0;
return function (...args){
if (new Date() - pre > wait) {
// 当 n 秒内不重复执行
pre = new Date();
event.apply(this, args)
}
}
}

使用时间戳虽然能实现节流,但是最后一次事件不会执行。

定时器

function throttle(event, wait) {
let timer = null;
return function (...args) {
if (!timer) {
timer = setTimeout(() => {
timer = null;
event.apply(this, args)
}, wait)
}
}
}

使用定时器实现节流,虽然最后一次能触发,但是第一次不会触发。

时间戳 + 定时器。

为解决第一次和最后一次都可以触发,把两者结合起来。

function throttle(event, wait) {
let pre = 0, timer = null;
return function (...args) {
if (new Date() - pre > wait) {
clearTimeout(timer);
timer = null;
pre = new Date();
event.apply(this, args)
} else {
timer = setTimeout(() => {
event.apply(this, args)
}, wait)
}
}
}

节流场景

scroll 滚动

window.addEventListener('scroll', throttle(handleScroll, 200))

input 动态搜索

throttle(fetchInput, 300)

节流帝王库

  • lodash-throttle。
  • underscore-throttle。

总结

防抖:只执行最后一次。事件持续触发,但只有等事件停止触发后 n 秒后才执行函数。

节流:控制执行频率。持续触发,每 n 秒执行一次函数。

对比图:

责任编辑:姜华 来源: 今日头条
相关推荐

2021-05-08 07:53:33

面试线程池系统

2020-11-24 07:48:32

React

2021-08-10 18:36:02

Express原理面试

2020-10-20 09:12:57

axios核心原理

2022-08-27 13:49:36

ES7promiseresolve

2020-10-23 09:26:57

React-Redux

2023-11-28 17:49:51

watch​computed​性能

2020-10-15 12:52:46

SpringbootJava编程语言

2022-10-31 11:10:49

Javavolatile变量

2021-04-22 07:49:51

Vue3Vue2.xVue3.x

2021-12-02 08:19:06

MVCC面试数据库

2023-12-18 07:37:17

JavaScript防抖节流

2019-06-17 05:03:37

memcache内核架构

2021-08-03 06:57:36

Js事件节流

2020-04-30 10:24:35

Spring循环依赖Java

2022-05-24 08:03:28

InnoDBMySQL数据

2020-04-16 08:22:11

HTTPS加解密协议

2021-05-20 08:54:16

Go面向对象

2010-08-23 15:06:52

发问

2021-06-03 08:55:54

分布式事务ACID
点赞
收藏

51CTO技术栈公众号