亲宝软件园·资讯

展开

js防抖-节流函数的基本实现和补充详解

既白biu 人气:0

前言

防抖和节流函数是我们在平常开发的时候,比较常用的两个工具函数,使用防抖和节流函数可以提高我们的效率,减小事件触发的频率,可以起到降低服务器压力的作用。并且在面试时候,这两个函数也是会经常会被问到,因此,了解防抖和节流函数的基本原理和应用场景,并且手写实现这两个函数至关重要

防抖函数

概念和应用场景

防抖函数:当事件触发的时候,并不会立刻执行,而是会等待一段事件,当事件密集触发时候,函数的触发会频繁的被推迟,只有等待了一段时间也没有事件触发,才会真正的执行。如下图所示:

防抖的应用场景很多:

  • 输入框中频繁的输入内容,搜索或者提交信息;
  • 频繁的点击按钮,触发某个事件;
  • 监听浏览器滚动事件,完成某些特定操作;
  • 用户缩放浏览器的resize事件

案例:

在某个搜索框中输入自己想要搜索的内容:

比如想要搜索一个MacBook:
当我输入m时,为了更好的用户体验,通常会出现对应的联想内容,这些联想内容通常是保存在服务器的,所以需要一次网络请求;当继续输入ma时,再次发送网络请求;
那么macbook一共需要发送7次网络请求; 这大大损耗我们整个系统的性能,无论是前端的事件处理,还是对于服务器的压力;

但是我们需要这么多次的网络请求吗?

不需要,正确的做法应该是在合适的情况下再发送网络请求; 比如如果用户快速的输入一个macbook,那么只是发送一次网络请求;
比如如果用户是输入一个m想了一会儿,这个时候m确实应该发送一次网络请求;
也就是我们应该监听用户在某个时间,比如500ms内,没有再次触发时间时,再发送网络请求;
这就是防抖的操作:只有在某个时间内,没有再次触发某个函数时,才真正的调用这个函数;

手写实现防抖函数

那么如何通过代码实现防抖的功能呢?

首先,防抖函数应该传入一个需要实现防抖的函数,还有一个时间,该时间表示在规定时间内,如果再次触发此次事件,则取消上次事件。返回的结果应该是一个执行了此功能的函数。

那么整体的框架如下,只需要在_debounce函数里面实现功能即可。

function debounce(fn,delay){
	const _debounce = function(){
	}
	return _debounce
}

函数的参数传进来一个时间,该时间表示在规定时间内,如果再次触发此次事件,则取消上次事件,所以需要有定时器来记录时间。并且有取消事件的过程,所以我们需要在满足条件时候,取消定时器,即clearTimeout,那么还有个问题,fn函数this指向。

如果在_debounce中单独调用传进来的函数fn,即以fn()形式直接调用,那么fn是属于独立的函数调用,this指向的是window,实际this指向的是调用函数的对象,所以会出现错误。

我们知道事件调用的时候,响应函数参数会传进来一个event事件对象,所以我们要对这个参数(event事件对象)做处理。

那么:

timer定义一个定时器,保存上一次的定时器,在_debounce函数里面,如果timer不为空,那么先清除上一次的定时器,之后再给timer赋值,让他延迟执行fn函数,fn函数用apply改变了this指向,在setTimeout内部使用的是箭头函数,由于箭头函数内部没有this,所以会去上层找this,那么这个this实际上就是调用debounce的对象。

比如输入框的输入事件做防抖处理:

const inputEl = document.querySelector(“input”)
inputChange是输入事件触发后所要执行的函数,可以给他做防抖处理:const debounceChange = debounce(inputChange,3000),然后执行: inputEl.oninput = debounceChange,如果不加防抖处理,毫无疑问,每次在输入框输入时候,都会触发事件,加了防抖处理后,3秒内多次调用,下一次事件会把上一次事件清除掉。

这里的this通过apply调用后,指向的就是inputEl这个元素,

function debounce(fn, delay) {
  // 1.定义一个定时器, 保存上一次的定时器
  let timer = null

  // 2.真正执行的函数
  const _debounce = function(...args) {
    // 取消上一次的定时器
    if (timer) clearTimeout(timer)
    // 延迟执行
    timer = setTimeout(() => {
      // 外部传入的真正要执行的函数
      fn.apply(this, args)
    }, delay)
  }

  return _debounce
}

节流函数

概念和应用场景

节流函数:当事件执行时候,会执行这个事件的响应函数;如果这个事件会被频繁触发,那么节流函数会按照一定的频率来执行函数;不管在这个中间有多少次触发这个事件,执行函数的频繁总是固定的;如图所示:

节流的应用场景:

  • 监听页面的滚动事件;
  • 鼠标移动事件;
  • 用户频繁点击按钮操作;
  • 游戏中的一些设计

节流的具体应用场景:
很多人都玩过类似于飞机大战的游戏

在飞机大战的游戏中,我们按下空格会发射一个子弹:

很多飞机大战的游戏中会有这样的设定,即使按下的频率非常快,子弹也会保持一定的频率来发射;

比如1秒钟只能发射一次,即使用户在这1秒钟按下了10次,子弹会保持发射一颗的频率来发射;

但是事件是触发了10次的,响应的函数只触发了一次

手写实现节流函数

那么如何通过代码实现防抖的功能呢?

首先,我们需要两个变量记录当前事件触发的时间和上一次的开始时间,函数的参数会传进来间隔的时间,由此我们可以计算出下次触发的最低间隔时间,即为间隔时间-(当前事件触发的时间-上次的开始时间),如果间隔时间<=0,那么执行fn函数,并且修改上一次的开始时间为当前事件触发时间。

function throttle(fn, interval) {
  // 1.记录上一次的开始时间
  let lastTime = 0

  // 2.事件触发时, 真正执行的函数
  const _throttle = function(...args) {

    // 2.1.获取当前事件触发时的时间
    const nowTime = new Date().getTime()

    // 2.2.使用当前触发的时间和之前的时间间隔以及上一次开始的时间, 计算出还剩余多长事件需要去触发函数
    const remainTime = interval - (nowTime - lastTime)
    if (remainTime <= 0) {
      // 2.3.真正触发函数
      fn.apply(this,args)
      // 2.4.保留上次触发的时间
      lastTime = nowTime
    }
  }

  return _throttle
}

加载全部内容

相关教程
猜你喜欢
用户评论