当前位置: 首页 > news >正文

使用requestAnimationFrame写防抖和节流

debounce.ts

防抖工具函数:

function Animate() {this.timer = null;
}Animate.prototype.start = function (fn) {if (!fn) {throw new Error('需要执行函数');}if (this.timer) {this.stop();}this.timer = requestAnimationFrame(fn);
}Animate.prototype.stop = function () {if (!this.timer) {return;}cancelAnimationFrame(this.timer);this.timer = null;
}export default Animate;

注意:

以上是es5写法,也可以自行改成es6的class类写法

使用示例:

import React, { useState, useEffect } from 'react';
import Animate from 'utils/debounce';export default function UseTransition() {const [isAnimationFrame, setIsAnimationFrame]= useState(false);const [rangeValue, setRangeValue] = useState(1);const [renderData, setRenderData] = useState([1]);const [isPending, setIsPending] = useState(false);const animate = new Animate();const handleRange = (e) => {const value = parseInt(e.target.value, 10);setRangeValue(value);// 模拟 startTransition 的效果setIsPending(true);// 使用 requestAnimationFrame 模拟异步操作const fn = () => {const arr = Array(value).fill(null).map((_, index) => index + 1);setRenderData(arr);setIsPending(false);animate.stop();}// 1000/60动画帧频率isAnimationFrame ? animate.start(fn): fn();};useEffect(() => {return () => {isAnimationFrame && animate.stop();};}, []);const jsx = renderData.map((item) => (<divkey={item}style={{width: 20,height: 20,backgroundColor: `#${Math.floor(Math.random() * 22222222).toString(16)}`,margin: 10,display: 'inline-block',}}>{item}</div>));return (<div><div style={{ textAlign: 'center' }}><label><inputtype="checkbox"checked={isAnimationFrame}onChange={(e) => {setIsAnimationFrame(e.target.checked)}}/>setIsAnimationFrame</label><inputtype="range"value={rangeValue}min={0}max={10000}style={{ width: 120 }}onChange={handleRange}/><span>进度条 {rangeValue}</span><span>{isPending ? 'loading' : ''}</span><hr /></div>{jsx}</div>);
}

throttle.ts

节流工具函数

function Animate() {this.timer = null;this.lastRun = 0;this.interval = 1000 / 60; // 默认每秒 60 帧,即约 16.67 毫秒
}Animate.prototype.start = function (fn, interval = 1000 / 60) {if (!fn) {throw new Error('需要执行函数');}this.interval = interval;// 高精度:performance.now() 返回的时间戳精度通常在微秒级别,而 Date.now() 的精度通常在毫秒级别。const now = performance.now();if (this.timer === null && (now - this.lastRun >= this.interval)) {this.lastRun = now;this.timer = requestAnimationFrame(() => {fn();this.timer = null;this.start(fn, interval); // 递归调用以继续动画});}
}Animate.prototype.stop = function () {if (!this.timer) {return;}cancelAnimationFrame(this.timer);this.timer = null;this.lastRun = 0;
}export default Animate;

使用示例:

import React, { useState, useEffect } from 'react';
import Animate from 'utils/throttle';export default function UseTransition() {const [isAnimationFrame, setIsAnimationFrame]= useState(false);const [rangeValue, setRangeValue] = useState(1);const [renderData, setRenderData] = useState([1]);const [isPending, setIsPending] = useState(false);const animate = new Animate();const handleRange = (e) => {const value = parseInt(e.target.value, 10);setRangeValue(value);// 模拟 startTransition 的效果setIsPending(true);// 使用 requestAnimationFrame 模拟异步操作const fn = () => {const arr = Array(value).fill(null).map((_, index) => index + 1);setRenderData(arr);setIsPending(false);animate.stop();}// 1000/60动画帧频率isAnimationFrame ? animate.start(fn, 1000/60): fn();};useEffect(() => {return () => {isAnimationFrame && animate.stop();};}, []);const jsx = renderData.map((item) => (<divkey={item}style={{width: 20,height: 20,backgroundColor: `#${Math.floor(Math.random() * 22222222).toString(16)}`,margin: 10,display: 'inline-block',}}>{item}</div>));return (<div><div style={{ textAlign: 'center' }}><label><inputtype="checkbox"checked={isAnimationFrame}onChange={(e) => {setIsAnimationFrame(e.target.checked)}}/>setIsAnimationFrame</label><inputtype="range"value={rangeValue}min={0}max={10000}style={{ width: 120 }}onChange={handleRange}/><span>进度条 {rangeValue}</span><span>{isPending ? 'loading' : ''}</span><hr /></div>{jsx}</div>);
}

防抖和节流的区别?

防抖(Debounce)

定义

  • 防抖是指在一系列连续的事件触发中,只在最后一次事件触发后的一段时间内执行一次回调函数。

特点

  • 忽略中间的调用,只在最后一次调用后执行。
  • 适用于需要在用户操作结束后再执行某些操作的场景,例如输入框的搜索建议、窗口的 resize 事件等。

节流(Throttle)

定义

  • 节流是指在一定时间间隔内最多执行一次回调函数。

特点

  • 在指定的时间间隔内,无论触发多少次事件,最多只执行一次回调函数。
  • 当前时间戳now 减去 上一次执行animate的时间戳lastRun的结果 >= 指定的时间间隔,则执行一次函数。
  • 适用于需要在固定时间间隔内执行某些操作的场景,例如滚动事件、鼠标移动事件等。
http://www.lryc.cn/news/473677.html

相关文章:

  • Puppeteer 与浏览器版本兼容性:自动化测试的最佳实践
  • Java方法重写
  • vscode通过.vscode/launch.json 内置php服务启动thinkphp 应用后无法加载路由解决方法
  • Webserver(2.6)有名管道
  • 四足机器人实战篇之一:波士顿spot机器人工程实现分析
  • TensorFlow 预训练目标检测模型集合
  • 字符串的区别
  • EMR Serverless Spark:一站式全托管湖仓分析利器
  • Linux find 匹配文件内容
  • 【Redis优化——如何优雅的设计key,优化BigKey,Pipeline批处理Key】
  • 数据结构与算法分析:你真的理解图算法吗——深度优先搜索(代码详解+万字长文)
  • LinkedList 分析
  • 【C/C++】模拟实现strlen
  • mybatis从浅入深一步步演变分析
  • Java阶段三02
  • 【Linux】掌握库的艺术:我的动静态库封装之旅
  • UE5动画控制 基础
  • 流畅!HTMLCSS打造网格方块加载动画
  • linux命令之top(Linux Command Top)
  • 数据结构-希尔排序(ShellSort)笔记
  • Junit + Mockito保姆级集成测试实践
  • 软件项目管理要点
  • ESP8266 连接 MQTT 服务器EMQX 连接MQTTX
  • Python中如何处理异常情况?
  • openpnp - 在openpnp中单独测试相机
  • Spark窗口函数
  • Idea、VS Code 如何安装Fitten Code插件使用
  • elasticsearch7.x在k8s中的部署
  • 校园社团信息管理平台:Spring Boot技术实战指南
  • 【Linux】从内核角度理解 TCP 的 全连接队列(以及什么是 TCP 抓包)