【随笔三】一篇文章理清 节流、防抖以及应用场景

前言

防抖节流 很多人特别容易把概念混倄,今天,一篇文章教你彻底理清其中的概念及应用场景。

先说共同点

防抖 和 节流 函数都是为了 限制函数的执行频次,从而优化函数触发频率过高导致的响应速度跟不上触发频率,导致出现延迟、卡顿的现象以及其他错误。 是常见的前端性能优化技巧。

但应用场景不同

防抖

防抖通常用来处理一些高频触发的事件,比如用户连续点击按钮、输入框频繁输入。

当用户点击按钮过快,导致重复点击,多次调用接口;或者输入框的文字一变化就调用接口,导致多次调用接口。

此时,我们肯定是希望哪怕多次点击按钮,也只调用一次接口;也不希望输入框每输入一个字母就发送一次请求,那样页面就会频繁地发送请求,极大的浪费资源。

使用防抖可以在用户输入完毕后再发送请求,或者避免重复点击按钮重复请求,减少函数的执行次数及接口调用,避免频繁更新UI或者发送请求造成性能浪费。

简单点来说:防抖 就是最后一次说了算。其核心就是:在某段时间内,不管触发了多少次回调,都只认最后一次。

四个字概括:等你到底

// 写一个简单的防抖函数
/**
 *	@param fn:需要用来防抖的方法,是一个回调
 *	@param wait: 时间间隔
 *	对于短时间内连续触发的事件,防抖可以用来在某个时间内(wait),事件处理函数只执行最后一次
 */
export const debounce = (fn: any, wait: num) => {
    
    
	let timer: any = null
	return () => {
    
    
		if(timer) {
    
    
			clearTimerout(timer)
		}
		timer = setTimeout(fn, wait)
	}
}

节流

节流: 是指对于连续触发的事件,每隔一段时间内执行一次,节流里面涉及的时间主要指时间执行的间隔时间。

通常用于一些高频率的事件中,比如 鼠标滚动、窗口resize、滚动条滑动 等操作。在这种情况下,我们希望这些事件能够以一定的频率触发(要触发多次),但不是每次事件都触发,节流函数可以规定在一定时间间隔中,该方法只执行一次。这样可以减少函数的执行次数,优化性能。

举个简单例子,当用户拖动滚动条时,如果每次滚动都触发事件,页面就会非常频繁的更新UI,造成卡顿。使用节流函数可以限制触发频率,提升页面流畅度。

简单点来说:节流 就是第一次说了算。其核心就是:在某段时间内,不管触发了多少次回调,都只认第一次。

时间戳节流

// 时间戳节流实现
function throttle(fn: any, wait: number) {
    
    
  let prev = 0;
  return function(...args) {
    
    
    const now = Date.now();
    if (now - prev >= delay) {
    
    
      fn(...args);
      prev = now;
    }
  };
}

上面的节流函数中,在每次事件触发时,判断当前时间和上一次触发事件的间隔是否超过指定的时间间隔 wait,如果超过了,则执行时间处理函数 fn,并更新上一次触发事件为当前时间。

写一个方法测试上面的节流函数。

// 测试
function log() {
    
    
  console.log('hello world');
}

const throttledLog = throttle(log, 3000);

setInterval(throttledLog, 50);

上面的代码中,本来是 50毫秒调用一次 throttleLog ,但由于设置了 3000 毫秒的节流时间间隔,所以,实际上,log 函数只会每隔 3000 毫秒 执行一次。

使用上面的 时间戳节流,还可以有另一种写法:限制在一定时间内触发事件次数:即我们自定义在一定时间间隔内,调用次数,做个限制,不过这里不做多说。

定时器节流

// 定时器节流
export const throttle = (fn: any, wait: number) => {
    
    
	let timer: any = null;
	return function(...args) {
    
    
		if(!timer) {
    
    
			timer = setTimeout(function() => {
    
    
				fn(...args);
				timer = null
			}, wait)
		}
	}
}

1. 节流中,timer 为什么要 等于 null?

首先我们要知道一件事:定时器是有返回值的,返回值是当前定时器的 ID号,clearTimeout(timer) ,会清除该定时器函数,但不会改变 id 值。从下图我们可以看出,使用clearTimeout并不会改变 timer 的ID号,但可以关闭定时器。


如果我们不将 timer 设置为 null,而是直接设置新的定时器 ID,那么就会无法清除之前的定时器,会导致多个定时器同时执行,达不到节流的效果。所以在每次执行定时器函数之前,将 timer 设置为 null,确保下次事件触发时能正确清除之前的定时器。

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_41131745/article/details/129635083