001什么是防抖和节流?有什么区别?如何实现?

103 阅读3分钟

一、什么是防抖和节流?有什么区别?如何实现?

1. 防抖和节流是什么?

​ 本质上是优化高频率执行代码的一种手段。

​ 如:浏览器的resizescrollkeypressmousemove 等事件在触发时,会不断的调用绑定在事件上的回调函数,极大地浪费资源、降低前端性能。

​ 为了优化体验,需要对这类事件进行调用次数的限制,对此我们就可以采用throttle(防抖)和(debounce)节流。

定义:

- 节流:n秒内只运行一次,若在n秒内重复出发,只有一次触发。
- 防抖:n秒后再执行该事件,若在n秒内被重复触发,则重新计时。

2. 代码实现

**节流 **

完成节流可以使用时间戳与定时器的写法

使用时间戳写法,事件会立即执行,停止触发后没有办法再次执行。

function throttled1(fn, delay = 500) {
	let oldTime = Date.now()
	return function (...args) {
		let newTime = Date.now()
		if(newTime - oldTime >= delay) {
			fn.apply(null, args)
			oldTime = Date.now()
		}
	}
}

​ 使用定时器写法,delay毫秒后第一次执行,第二次事件停止触发后依然会再一次执行。

function throttled2(fn, delay = 500) {
	let timer = null
	return function (...args) {
		if(!timer) {
			timer = setTimeout(()=>{
				fn.apply(this, args)
				timer = null
			},delay)
		}
	}
}

可以将时间戳写法的特性与定时器写法的特性相结合,实现一个更加精确地节流。实现如下:

function throttled(fn, delay) {
	let timer = null
	let starttime = Date.now()
	return function () {
		let curTime = Date.now() // 当前时间
		let remaining = delay -(curTime - startTime) // 从上一次到现在,还剩下多少时间。
		let context = this
		let args = arguments
		clearTimeout(timer)
		if(remaining <=0 ) {
			fn.apply(context, args)
			startTime = Date.now()
		} else {
			timer = setTimeout(fn,remaining)
		}
		
	}
}

防抖

简单版本的实现

function debounce(func, wait) {
	let timeout
	return function() {
		let context = this //保存this指向
		let args = arguments // 拿到event对象
		clearTimeout(timeout)
		timeout = setTimeout(function(){
			func.apply(context, args)
		},wait)
	}
}

防抖如果需要立即执行,可加入第三个参数用于判断,实现如下:

function debounce(fun, wait, immediate) {
	let timeout
	return function() {
		let context = this
		let args = arguments
		if(timeout) clearTimeout(timeout) 
		if(immediate) {
			let callNow = !timeout  // 第一次会立即执行,以后只有事件执行后才会再次触发
			timeout = setTimeout(function() {
			timeout = null
			},wait)
			if(callNow) {
				func.applay(context, args)
			}
		} else {
			timeout = setTimeout(function(){
				func.apply(context, args)
			},wait)
		}
	}
}

3.区别

相同点:

  • 都可以通过使用setTimeout实现
  • 目的都是,降低回调执行频率,节省计算资源。

不同点:

  • 函数防抖,在一段连续操作结束后,处理回调,利用clearTimeout 和setTimeout实现。

    函数节流,在一段连续操作中,每一段时间只执行一次,频率较高的事件中使用来提高性能。

  • 函数防抖关注一定时间连续触发的事件,只在最后执行一次,而函数节流一段时间内只执行一次。

例如:都设置事件频率为500ms,在2秒钟内,频繁触发函数。

节流:每隔500ms就执行一次。

防抖:不管调用多少次方法,在2秒后,只会执行一次。

4. 应用场景

防抖在连续的事件,只需触发一次回调的场景有:

  • 搜索框搜索输入。只需用户最后一次输完,再发送请求。
  • 手机号、邮箱验证输入检测。
  • 窗口大小resize。只需再窗口调整完成后,计算窗口大小。防止重复渲染。

节流在间隔一段时间执行一次回调的场景有:

  • 滚动加载,加载更多或滚动到底部监听
  • 搜索框,搜索联想功能

Vue使用lodash插件实现防抖和节流

1.使用lodash插件

  1. 下载插件lodash
  2. lodash对外暴露的函数是 _
import _ from 'lodash'

2.防抖的函数 _.debounce()

// 防抖
getList:_.debounce(function(){
	this.getUserList()
},2000)

3.节流的函数 _.throttle()

// 节流
getList:_.throttle(function() {
	this.getUserList()
},2000)