【JavaScript】函数防抖(debounce)、函数节流(throttle)在面向切片编程(AOP)中的应用

什么是面向切面编程

面向切面编程(Aspect-Oriented Programming,AOP)是一种编程范式,是在面向对象编程(OOP)的基础上的一种补充。AOP提供了一种灵活的、易于维护和跨多个对象和组件的切面(Aspect)的方式,可以在不修改原有代码的情况下实现代码的特定功能。

下面是一个简单的JS示例代码,实现了AOP的日志记录功能:

js 复制代码
//定义一个用于包装函数的高阶函数
function Logging(fn) {
  return function() {
    console.log(`entering ${fn.name}`);
    const result = fn.apply(this, arguments);
    console.log(`exiting ${fn.name}`);
    return result;
  }
}

//定义一个需要包装的函数
function add(x, y) {
  return x + y;
}

//将函数用Logging包装
const loggedAdd = Logging(add);

//调用经过包装的函数
loggedAdd(2, 3);

在上面的代码中,Logging是一个高阶函数(Higher Order Function),它返回的函数可以包装一个函数,并能够记录该函数的输入和输出。add是一个需要包装的函数,它的功能是相加两个数。用Logging包装add得到的loggedAdd函数,可以在add函数执行前输出"entering add",在add函数执行后输出"exiting add",并返回add函数的执行结果。

只不过这样的使用方式不太友好,怎么才能更加简单呢,在VUE、Recat、Angular等框架中常见的装饰是个比较好的方式。

装饰器

JavaScript中的装饰器是一种特殊的函数,它可以用来修改类或对象的行为。装饰器可以在不修改原始类或对象定义的情况下,动态地添加、删除或修改它们的属性和方法。

装饰器可以被用来解决很多问题,比如增加验证、日志记录、性能分析等功能,这些功能可以通过在类或对象的定义上应用不同的装饰器来实现。使用装饰器可以让代码具有更好的可维护性和可扩展性。

通常情况下,装饰器可以在函数、类、类成员上应用。

我们准备对防抖和节流这两个最常用的函数进行升级。升级前先看看最基本的使用方式。

函数防抖(debounce)

概念: 在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。

生活中的实例: 如果有人进电梯(触发事件),那电梯将在10秒钟后出发(执行事件监听器),这时如果又有人进电梯了(在10秒内再次触发该事件),我们又得等10秒再出发(重新计时)。

JS函数防抖:

js 复制代码
function debounce(fn, wait) {
  var timer = null;
  return function () {
      var context = this
      var args = arguments
      if (timer) {
          clearTimeout(timer);
          timer = null;
      }
      timer = setTimeout(function () {
          fn.apply(context, args)
      }, wait)
  }
}

var fn = function () {
  console.log('boom')
}

setInterval(debounce(fn,500),1000) // 第一次在1500ms后触发,之后每1000ms触发一次

setInterval(debounce(fn,2000),1000) // 不会触发一次(我把函数防抖看出技能读条,如果读条没完成就用技能,便会失败而且重新读条)

函数节流(throttle)

概念: 规定一个单位时间,在这个单位时间内,只能有一次触发事件的回调函数执行,如果在同一个单位时间内某事件被触发多次,只有一次能生效。

生活中的实例: 我们知道目前的一种说法是当 1 秒内连续播放 24 张以上的图片时,在人眼的视觉中就会形成一个连贯的动画,所以在电影的播放(以前是,现在不知道)中基本是以每秒 24 张的速度播放的,为什么不 100 张或更多是因为 24 张就可以满足人类视觉需求的时候,100 张就会显得很浪费资源。

JS函数节流:

js 复制代码
function throttle(fn, gapTime) {
  let _lastTime = null;

  return function () {
    let _nowTime = + new Date()
    if (_nowTime - _lastTime > gapTime || !_lastTime) {
      fn();
      _lastTime = _nowTime
    }
  }
}

let fn = ()=>{
  console.log('boom')
}

setInterval(throttle(fn,1000),10)

在使用上面的函数时我们要对原有的函数进行调整,增加业务逻辑,改动起来比较麻烦。

使用装饰器封装函数防抖和函数节流,代码如下:

装饰器-函数防抖

js 复制代码
/**
 * 函数防抖
 * @export
 * @param {*} delay
 * @returns {(target, name, descriptor) => any}
 */
export function debounce(delay) {
  let timer: any = null;
  return function (target, name, descriptor) {
    const originFn = descriptor.value;
    descriptor.value = function (...args) {
      if (timer) {
        clearTimeout(timer);
      }
      timer = setTimeout(() => {
        originFn.apply(this, args);
      }, delay);
    }
    return descriptor;
  }
}

装饰器-函数节流

js 复制代码
/**
 * 函数节流
 * @param {function} fn 函数
 * @param {number} delay 延迟执行毫秒数
 * @returns {(target: any, name: string, descriptor: PropertyDescriptor) => any}
 */
export function throttle(delay) {
    let timer: any = null;
    return function (target, name, descriptor) {
      const originFn = descriptor.value;
      descriptor.value = function (...args) {
        if (timer) {
            return;
        }
        timer = setTimeout(() => {
          originFn.apply(this, args);
          timer = undefined;
        }, delay);
      }
      return descriptor;
    }
}

使用方式比较简单,在需要处理的函数上添加上装饰器就行。

js 复制代码
// 函数防抖
@debounce(100)
init(){
    ......
}

// 函数节流
@throttle(100)
init(){
    ......
}

这样在使用时不会影响到原始的函数,代码也不需要进行调整。完美!!

加个关注,不迷路

相关推荐
剑之所向16 分钟前
.NET 官方`System.Threading.Channels`
前端·javascript·数据库
渡我白衣2 小时前
并查集:基础认识与模拟实现
android·java·javascript·数据结构·c++·算法·并查集
八角丶3 小时前
Node 网络编程 —— TLS 模块
javascript·后端·node.js
倔强的石头1063 小时前
【Linux指南】动静态库系列(七):符号表与重定位:链接器如何把函数调用接起来
linux·前端·javascript
图扑软件4 小时前
中篇・运笔|统一 DataModel 底座,HT UI 组件万物同源
javascript·低代码·ui·性能优化·数据可视化
小小尚@5 小时前
WebGIS/ECharts 地图开发|MapLand 在线行政区划边界一键下载 GeoJSON 工具
前端·javascript·echarts
葡萄城技术团队5 小时前
工业数据可视化:使用活字格 AIcoding + Three.js 构建轻量化三维设备监控大屏
开发语言·javascript·信息可视化
默_笙6 小时前
🚍 一条 Todo 的奇幻漂流:TypeScript 全栈类型安全的"护照检查"
前端·javascript
weixin_422555427 小时前
el-menu子菜单点击就被激活,恢复之前的激活状态
javascript·vue.js·elementui
Tanjia_kiki9 小时前
谷歌浏览器中F12编辑并重发请求
开发语言·前端·javascript