工程化与框架系列(22)--前端性能优化(中)
前端性能优化(运行) 🏃
引言
运行时性能直接影响用户交互体验和应用流畅度。本文将深入探讨前端运行时性能优化的各种策略和技术,包括渲染优化、内存管理、计算优化等关键主题,帮助开发者构建高性能的Web应用。
运行时性能概述
运行时性能优化主要关注以下方面:
- 渲染性能:减少重排重绘,优化动画效果
- 内存管理:防止内存泄漏,优化内存使用
- 计算优化:提升JavaScript执行效率
- 事件处理:优化事件监听和响应
- 异步操作:合理使用异步编程
渲染性能优化
DOM操作优化
// DOM操作优化工具
class DOMOptimizer {private static documentFragment: DocumentFragment;// 批量DOM更新static batchUpdate(elements: HTMLElement[]): void {this.documentFragment = document.createDocumentFragment();elements.forEach(element => {this.documentFragment.appendChild(element);});document.body.appendChild(this.documentFragment);}// 虚拟滚动实现static createVirtualScroller(container: HTMLElement,items: any[],itemHeight: number,renderItem: (item: any) => HTMLElement): void {const totalHeight = items.length * itemHeight;const visibleItems = Math.ceil(container.clientHeight / itemHeight);container.style.height = `${totalHeight}px`;let startIndex = 0;let endIndex = visibleItems;const render = () => {container.innerHTML = '';const fragment = document.createDocumentFragment();for (let i = startIndex; i < endIndex; i++) {if (items[i]) {const element = renderItem(items[i]);element.style.position = 'absolute';element.style.top = `${i * itemHeight}px`;fragment.appendChild(element);}}container.appendChild(fragment);};container.addEventListener('scroll', () => {const scrollTop = container.scrollTop;startIndex = Math.floor(scrollTop / itemHeight);endIndex = startIndex + visibleItems;requestAnimationFrame(render);});render();}// 防止布局抖动static preventLayoutThrashing(callback: () => void): void {requestAnimationFrame(() => {const measurements = [];// 读取阶段measurements.push(document.body.scrollHeight);measurements.push(document.body.offsetHeight);// 写入阶段callback();});}
}// 使用示例
const elements = Array.from({ length: 1000 }, (_, i) => {const div = document.createElement('div');div.textContent = `Item ${i}`;return div;
});DOMOptimizer.batchUpdate(elements);// 虚拟滚动示例
const container = document.getElementById('scroll-container')!;
const items = Array.from({ length: 10000 }, (_, i) => ({ id: i, text: `Item ${i}` }));DOMOptimizer.createVirtualScroller(container,items,50,item => {const div = document.createElement('div');div.textContent = item.text;return div;}
);
动画性能优化
// 动画优化工具
class AnimationOptimizer {// 使用requestAnimationFrame实现动画static animate(element: HTMLElement,properties: { [key: string]: number },duration: number,easing: (t: number) => number = t => t): Promise<void> {return new Promise(resolve => {const startValues: { [key: string]: number } = {};const startTime = performance.now();// 记录初始值for (const prop in properties) {startValues[prop] = parseFloat(getComputedStyle(element)[prop]) || 0;}const tick = (currentTime: number) => {const elapsed = currentTime - startTime;const progress = Math.min(elapsed / duration, 1);const easedProgress = easing(progress);// 更新属性值for (const prop in properties) {const start = startValues[prop];const end = properties[prop];const current = start + (end - start) * easedProgress;element.style[prop as any] = `${current}px`;}if (progress < 1) {requestAnimationFrame(tick);} else {resolve();}};requestAnimationFrame(tick);});}// GPU加速static enableGPUAcceleration(element: HTMLElement): void {element.style.transform = 'translateZ(0)';element.style.willChange = 'transform';}// 优化动画帧率static optimizeFrameRate(callback: () => void,targetFPS: number = 60): () => void {let lastTime = 0;const interval = 1000 / targetFPS;const animate = (currentTime: number) => {if (currentTime - lastTime >= interval) {callback();lastTime = currentTime;}return requestAnimationFrame(animate);};const animationId = requestAnimationFrame(animate);return () => cancelAnimationFrame(animationId);}
}// 使用示例
const element = document.getElementById('animated-element')!;// 启用GPU加速
AnimationOptimizer.enableGPUAcceleration(element);// 执行平滑动画
AnimationOptimizer.animate(element,{ left: 500, top: 300 },1000,t => t * t // 二次缓动
);// 优化动画帧率
const stopAnimation = AnimationOptimizer.optimizeFrameRate(() => {// 动画逻辑element.style.transform = `rotate(${Date.now() / 1000 * 360}deg)`;
}, 30); // 30FPS
内存管理优化
内存泄漏防护
// 内存管理工具
class MemoryManager {private static eventListeners: Map<HTMLElement, Set<Function>> = new Map();// 安全地添加事件监听器static addEventListenerSafely(element: HTMLElement,eventType: string,handler: Function): void {if (!this.eventListeners.has(element)) {this.eventListeners.set(element, new Set());}this.eventListeners.get(element)!.add(handler);element.addEventListener(eventType, handler as EventListener);}// 清理事件监听器static removeEventListeners(element: HTMLElement): void {const listeners = this.eventListeners.get(element);if (listeners) {listeners.forEach(handler => {element.removeEventListener('click', handler as EventListener);});this.eventListeners.delete(element);}}// 清理DOM引用static cleanupDOMReferences(root: HTMLElement): void {const elements = root.getElementsByTagName('*');for (const element of elements) {// 清理事件监听器this.removeEventListeners(element as HTMLElement);// 清理数据delete (element as any).dataset;// 清理自定义属性for (const prop in element) {if ((element as any)[prop]?.remove) {(element as any)[prop].remove();}}}}// 监控内存使用static monitorMemoryUsage(threshold: number = 100): void {if ('memory' in performance) {setInterval(() => {const usage = (performance as any).memory.usedJSHeapSize / 1024 / 1024;if (usage > threshold) {console.warn(`内存使用超过阈值: ${usage.toFixed(2)}MB`);// 触发垃圾回收this.forceGarbageCollection();}}, 5000);}}// 强制垃圾回收(仅供开发环境使用)private static forceGarbageCollection(): void {if ('gc' in window) {(window as any).gc();}}
}// 使用示例
const container = document.getElementById('container')!;// 安全地添加事件监听器
MemoryManager.addEventListenerSafely(container,'click',() => console.log('Clicked')
);// 组件卸载时清理
function unmountComponent(root: HTMLElement): void {MemoryManager.cleanupDOMReferences(root);root.remove();
}// 监控内存使用
MemoryManager.monitorMemoryUsage(150); // 150MB阈值
对象池优化
// 对象池实现
class ObjectPool<T> {private pool: T[] = [];private createFn: () => T;private resetFn: (obj: T) => void;constructor(createFn: () => T,resetFn: (obj: T) => void,initialSize: number = 0) {this.createFn = createFn;this.resetFn = resetFn;// 初始化对象池for (let i = 0; i < initialSize; i++) {this.pool.push(this.createFn());}}// 获取对象acquire(): T {return this.pool.pop() || this.createFn();}// 释放对象release(obj: T): void {this.resetFn(obj);this.pool.push(obj);}// 清空对象池clear(): void {this.pool = [];}
}// 使用示例
interface Particle {x: number;y: number;velocity: { x: number; y: number };active: boolean;
}const particlePool = new ObjectPool<Particle>(// 创建函数() => ({x: 0,y: 0,velocity: { x: 0, y: 0 },active: false}),// 重置函数particle => {particle.x = 0;particle.y = 0;particle.velocity.x = 0;particle.velocity.y = 0;particle.active = false;},1000 // 初始大小
);// 使用对象池创建粒子系统
class ParticleSystem {private particles: Particle[] = [];createParticle(x: number, y: number): void {const particle = particlePool.acquire();particle.x = x;particle.y = y;particle.velocity.x = Math.random() * 2 - 1;particle.velocity.y = Math.random() * 2 - 1;particle.active = true;this.particles.push(particle);}update(): void {for (let i = this.particles.length - 1; i >= 0; i--) {const particle = this.particles[i];particle.x += particle.velocity.x;particle.y += particle.velocity.y;if (particle.x < 0 || particle.x > window.innerWidth ||particle.y < 0 || particle.y > window.innerHeight) {// 回收粒子particlePool.release(particle);this.particles.splice(i, 1);}}}
}
计算性能优化
高性能计算
// 计算优化工具
class ComputeOptimizer {// Web Worker管理private static workers: Map<string, Worker> = new Map();// 创建计算Workerstatic createComputeWorker(taskName: string,workerScript: string): Worker {const worker = new Worker(workerScript);this.workers.set(taskName, worker);return worker;}// 执行密集计算static async computeIntensive(taskName: string,data: any): Promise<any> {const worker = this.workers.get(taskName);if (!worker) {throw new Error(`Worker not found for task: ${taskName}`);}return new Promise((resolve, reject) => {worker.onmessage = (e) => resolve(e.data);worker.onerror = (e) => reject(e);worker.postMessage(data);});}// 终止计算static terminateCompute(taskName: string): void {const worker = this.workers.get(taskName);if (worker) {worker.terminate();this.workers.delete(taskName);}}// 批量数据处理static processBatch<T, R>(items: T[],processor: (item: T) => R,batchSize: number = 1000): Promise<R[]> {return new Promise(resolve => {const results: R[] = [];let index = 0;const processNextBatch = () => {const end = Math.min(index + batchSize, items.length);while (index < end) {results.push(processor(items[index]));index++;}if (index < items.length) {setTimeout(processNextBatch, 0);} else {resolve(results);}};processNextBatch();});}
}// 使用示例
// 创建计算Worker
const computeWorker = ComputeOptimizer.createComputeWorker('matrix-multiply','/workers/matrix-worker.js'
);// 执行密集计算
async function multiplyLargeMatrices(matrix1: number[][], matrix2: number[][]) {try {const result = await ComputeOptimizer.computeIntensive('matrix-multiply',{ matrix1, matrix2 });return result;} catch (error) {console.error('计算失败:', error);throw error;}
}// 批量处理数据
const items = Array.from({ length: 10000 }, (_, i) => i);
const results = await ComputeOptimizer.processBatch(items,item => item * item,1000
);
防抖与节流
// 性能优化装饰器
class PerformanceDecorators {// 防抖装饰器static debounce(delay: number = 300): MethodDecorator {return function (target: any,propertyKey: string | symbol,descriptor: PropertyDescriptor) {const original = descriptor.value;let timeoutId: NodeJS.Timeout;descriptor.value = function (...args: any[]) {clearTimeout(timeoutId);timeoutId = setTimeout(() => {original.apply(this, args);}, delay);};return descriptor;};}// 节流装饰器static throttle(limit: number = 300): MethodDecorator {return function (target: any,propertyKey: string | symbol,descriptor: PropertyDescriptor) {const original = descriptor.value;let lastRun: number = 0;descriptor.value = function (...args: any[]) {const now = Date.now();if (now - lastRun >= limit) {lastRun = now;original.apply(this, args);}};return descriptor;};}// 性能监控装饰器static measurePerformance(): MethodDecorator {return function (target: any,propertyKey: string | symbol,descriptor: PropertyDescriptor) {const original = descriptor.value;descriptor.value = function (...args: any[]) {const start = performance.now();const result = original.apply(this, args);const end = performance.now();console.log(`${String(propertyKey)} 执行时间: ${end - start}ms`);return result;};return descriptor;};}
}// 使用示例
class SearchComponent {@PerformanceDecorators.debounce(300)async search(query: string): Promise<void> {// 搜索逻辑const results = await fetch(`/api/search?q=${query}`);// 处理结果}@PerformanceDecorators.throttle(1000)handleScroll(): void {// 滚动处理逻辑}@PerformanceDecorators.measurePerformance()computeExpensiveOperation(): void {// 复杂计算逻辑}
}
事件处理优化
事件委托
// 事件优化工具
class EventOptimizer {// 事件委托static delegate(element: HTMLElement,eventType: string,selector: string,handler: (e: Event, target: HTMLElement) => void): void {element.addEventListener(eventType, (event) => {const target = event.target as HTMLElement;const delegateTarget = target.closest(selector);if (delegateTarget && element.contains(delegateTarget)) {handler(event, delegateTarget as HTMLElement);}});}// 批量事件处理static batchEventProcessing<T>(handler: (items: T[]) => void,delay: number = 100): (item: T) => void {const batch: T[] = [];let timeoutId: NodeJS.Timeout;return (item: T) => {batch.push(item);clearTimeout(timeoutId);timeoutId = setTimeout(() => {handler(batch.splice(0));}, delay);};}// 事件优化装饰器static optimizeEventHandler(): MethodDecorator {return function (target: any,propertyKey: string | symbol,descriptor: PropertyDescriptor) {const original = descriptor.value;descriptor.value = function (...args: any[]) {requestAnimationFrame(() => {original.apply(this, args);});};return descriptor;};}
}// 使用示例
const list = document.getElementById('list')!;// 使用事件委托处理列表点击
EventOptimizer.delegate(list,'click','.item',(event, target) => {console.log('Clicked item:', target.textContent);}
);// 批量处理事件
const batchProcessor = EventOptimizer.batchEventProcessing<string>(items => {console.log('Processing batch:', items);}
);// 优化的事件处理器
class UIHandler {@EventOptimizer.optimizeEventHandler()handleResize(): void {// 处理调整大小的逻辑}
}
异步操作优化
Promise优化
// 异步操作优化工具
class AsyncOptimizer {// Promise并发控制static async concurrent<T>(tasks: (() => Promise<T>)[],concurrency: number = 3): Promise<T[]> {const results: T[] = [];const executing: Promise<void>[] = [];for (const task of tasks) {const p = Promise.resolve().then(() => task());results.push(p);if (concurrency <= tasks.length) {const e: Promise<void> = p.then(() => {executing.splice(executing.indexOf(e), 1);});executing.push(e);if (executing.length >= concurrency) {await Promise.race(executing);}}}return Promise.all(results);}// 异步重试机制static async retry<T>(fn: () => Promise<T>,retries: number = 3,delay: number = 1000): Promise<T> {try {return await fn();} catch (error) {if (retries === 0) throw error;await new Promise(resolve => setTimeout(resolve, delay));return this.retry(fn, retries - 1, delay * 2);}}// 异步缓存static memoizeAsync<T>(fn: (...args: any[]) => Promise<T>,ttl: number = 60000): (...args: any[]) => Promise<T> {const cache = new Map<string, { value: T; timestamp: number }>();return async (...args: any[]): Promise<T> => {const key = JSON.stringify(args);const cached = cache.get(key);if (cached && Date.now() - cached.timestamp < ttl) {return cached.value;}const result = await fn(...args);cache.set(key, { value: result, timestamp: Date.now() });return result;};}
}// 使用示例
// 并发控制
const tasks = Array.from({ length: 10 }, (_, i) => async () => {await new Promise(resolve => setTimeout(resolve, Math.random() * 1000));return i;
});const results = await AsyncOptimizer.concurrent(tasks, 3);// 异步重试
const fetchWithRetry = async () => {return await AsyncOptimizer.retry(async () => {const response = await fetch('/api/data');if (!response.ok) throw new Error('Request failed');return response.json();},3,1000);
};// 异步缓存
const memoizedFetch = AsyncOptimizer.memoizeAsync(async (url: string) => {const response = await fetch(url);return response.json();},60000 // 1分钟缓存
);
最佳实践与建议
-
渲染优化
- 避免频繁的DOM操作
- 使用DocumentFragment进行批量更新
- 实现虚拟滚动
- 优化动画性能
-
内存管理
- 及时清理事件监听器
- 使用对象池复用对象
- 避免闭包导致的内存泄漏
- 定期监控内存使用
-
计算优化
- 使用Web Worker处理密集计算
- 实现数据的批量处理
- 合理使用防抖和节流
- 优化循环和递归
-
事件处理
- 使用事件委托
- 批量处理事件
- 优化事件监听器
- 使用requestAnimationFrame
总结
前端运行时性能优化是一个系统工程,需要从多个维度进行优化:
- 优化渲染性能
- 合理管理内存
- 提升计算效率
- 优化事件处理
- 改进异步操作
通过合理运用这些优化策略,可以显著提升Web应用的运行时性能,为用户提供流畅的交互体验。
学习资源
- 浏览器渲染原理
- JavaScript性能优化指南
- Web Worker使用指南
- 内存管理最佳实践
- 异步编程进阶
如果你觉得这篇文章有帮助,欢迎点赞收藏,也期待在评论区看到你的想法和建议!👇
终身学习,共同成长。
咱们下一期见
💻
相关文章:
工程化与框架系列(22)--前端性能优化(中)
前端性能优化(运行) 🏃 引言 运行时性能直接影响用户交互体验和应用流畅度。本文将深入探讨前端运行时性能优化的各种策略和技术,包括渲染优化、内存管理、计算优化等关键主题,帮助开发者构建高性能的Web应用。 运行…...
API调试工具的无解困境:白名单、动态IP与平台设计问题
引言 你是否曾经在开发中遇到过这样的尴尬情形:你打开了平台的API调试工具,准备一番操作,结果却发现根本无法连接到平台?别急,问题出在调试工具本身。今天我们要吐槽的就是那些神奇的开放平台API调试工具,…...
C#模拟鼠标点击,模拟鼠标双击,模拟鼠标恒定速度移动,可以看到轨迹
C#模拟鼠标点击,模拟鼠标双击,模拟鼠标恒定速度移动,可以看到轨迹 using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks;namespa…...
php虚拟站点提示No input file specified时的问题及权限处理方法
访问站点,提示如下 No input file specified. 可能是文件权限有问题,也可能是“.user.ini”文件路径没有配置对,最简单的办法就是直接将它删除掉,还有就是将它设置正确 #配置成自己服务器上正确的路径 open_basedir/mnt/qiy/te…...
RISC-V汇编学习(三)—— RV指令集
有了前两节对于RISC-V汇编、寄存器、汇编语法等的认识,本节开始介绍RISC-V指令集和伪指令。 前面说了RISC-V的模块化特点,是以RV32I为作为ISA的核心模块,其他都是要基于此为基础,可以这样认为:RISC-V ISA 基本整数指…...
java 重点知识 — JVM存储模块与类加载器
1 jvm主要模块 方法区 存储了由类加载器从.class文件中解析的类的元数据(类型信息、域信息、方法信息)及运行时常量池(引用符号及字面量)。 所有线程共享;内存不要求连续,可扩展,可能发生垃圾回…...
WPF有哪些使用率高的框架
架构类库 Community Toolkit MVVMMVVM Light UI类库 MahApps.MetroMaterial Design In XAML Toolkit 图标类库 MahApps.Metro.IconPacks...
idea中使用DeepSeek让编程更加便捷
IDEA中使用DeepSeek让编程更加便捷 对于开发者来说,IDEA(IntelliJ IDEA)是一款强大的开发工具。但你是否知道,通过安装DeepSeek这款插件,可以让你的编程体验更上一层楼?今天,我们就来聊聊如何在…...
创建Electron35 + vue3 + electron-builder项目,有很过坑,记录过程
环境: node v20.18.0 npm 11.1.0 用到的所有依赖: "dependencies": {"core-js": "^3.8.3","vue": "^3.2.13","vue-router": "^4.5.0"},"devDependencies": {"ba…...
elasticsearch是哪家的
Elasticsearch:数据搜索与分析的领航者 在当今这个信息爆炸的时代,快速且准确地处理海量数据成为了众多企业和组织追求的目标。而Elasticsearch正是在这个背景下脱颖而出的一款强大的开源搜索引擎。它是由位于美国加利福尼亚州的Elastic公司所开发和维护…...
nginx基础http基础
目录 nginx简介正向代理&反向代理正向代理反向代理What Is a Reverse Proxy Server? High-Performance Load Balancing (负载均衡)Problem(问题)Solution(解决方案)常见负载均衡算法Round Robin(轮询)…...
5. MySQL 存储引擎(详解说明)
5. MySQL 存储引擎(详解说明) 文章目录 5. MySQL 存储引擎(详解说明)1. 查看存储引擎2. 设置系统默认的存储引擎3. 设置表的存储引擎3.1 创建表时指定存储引擎3.2 修改表的存储引擎 4. 引擎介绍4.1 InnoDB 引擎:具备外键支持功能的事务存储引擎4.2 MyISAM 引擎&…...
基于LabVIEW的伺服阀高频振动测试闭环控制系统
为实现伺服阀在设定位置上下快速移动(1kHz控制频率)的振动测试目标,需构建基于LabVIEW的闭环控制系统。系统需满足高速数据采集、实时控制算法(如PID或自适应控制)、高精度电流驱动及传感器反馈处理等需求。结合用户提…...
97.在 Vue 3 中使用 OpenLayers 根据两行根数 (TLE) 计算并显示卫星轨迹(EPSG:3857)
前言 在许多卫星应用场景中,我们需要 基于 TLE(Two-Line Element Set, 两行根数)计算卫星轨迹,并在地图上进行可视化。本文将使用 Vue 3 OpenLayers satellite.js,实现 实时计算卫星轨迹,并在地图上动态更…...
Android Coil总结
文章目录 Android Coil总结概述添加依赖用法基本用法占位图变形自定义ImageLoader取消加载协程支持缓存清除缓存监听 简单封装 Android Coil总结 概述 Coil 是一个用于 Android 的 Kotlin 图像加载库,旨在简化图像加载和显示的过程。它基于 Kotlin 协程࿰…...
fastjson漏洞#不出网#原理#流量特征
原理 本质是java的反序列化漏洞,由于引进了自动检测类型的(autotype)功能,fastjson在对json字符串反序列化的时候,会读取type内容,会试图将json内容反序列化成这个对象,并调用这个类的setter方…...
云计算:虚拟化、容器化与云存储技术详解
在上一篇中,我们深入探讨了网络安全的核心技术,包括加密、认证和防火墙,并通过实际案例和细节帮助读者全面理解这些技术的应用和重要性。今天,我们将转向一个近年来迅速发展的领域——云计算。云计算通过提供按需访问的计算资源,彻底改变了IT基础设施的构建和管理方式。本…...
使用 marked.min.js 实现 Markdown 编辑器 —— 我的博客后台选择之旅
最近,我决定为个人博客后台换一个编辑器。之前的富文本编辑器虽然功能齐全,但生成的 HTML 代码繁杂,维护起来非常麻烦。为了追求更简洁高效的写作体验,我开始研究 Markdown 编辑器,并最终选择了 marked.min.js。 1. 传…...
Linux系统基于ARM平台的LVGL移植
软硬件介绍:Ubuntu 20.04 ARM 和(Cortex-A53架构)开发板 基本原理 LVGL图形库是支持使用Linux系统的Framebuffer帧缓冲设备实现的,如果想要实现在ARM开发板上运行LVGL图形库,那么就需要把LVGL图形库提供的关于帧缓冲设…...
LeetCode 2070.每一个查询的最大美丽值:排序 + 二分查找
【LetMeFly】2070.每一个查询的最大美丽值:排序 二分查找 力扣题目链接:https://leetcode.cn/problems/most-beautiful-item-for-each-query/ 给你一个二维整数数组 items ,其中 items[i] [pricei, beautyi] 分别表示每一个物品的 价格 和…...
电力场景绝缘子缺陷分割数据集labelme格式1585张4类别
数据集格式:labelme格式(不包含mask文件,仅仅包含jpg图片和对应的json文件) 图片数量(jpg文件个数):1585 标注数量(json文件个数):1585 标注类别数:4 标注类别名称:["broken part","broken insulat…...
【计算机网络】深入解析 HTTP 协议的概念、工作原理和通过 Fiddler 抓包查看 HTTP 请求/响应的协议格式
网络原理— HTTP 1. 什么是HTTP? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议: HTTP 往往是基于传输层的 TCP 协议实现的 (HTTP1.0,HTTP1.1,HTTP2.0 均为TCP,HTTP3基于UDP实现) 我们平时打开一个网站,就是通过HTTP协议来…...
IPFS:下一代互联网传输协议
IPFS:下一代互联网传输协议 1. 引言2. IPFS概述3. IPFS的核心优势3.1 去中心化3.2 高效性3.3 安全性3.4 持久性3.5 可扩展性 4. IPFS的工作原理4.1 内容寻址4.2 分布式哈希表(DHT)4.3 文件分块4.4 版本控制4.5 网络协议 5. IPFS的应用场景5.1…...
线上接口tp99突然升高如何排查?
当线上接口的 TP99 突然升高时,意味着该接口在 99% 的情况下响应时间变长,这可能会严重影响系统的性能和用户体验。可以按照下面的步骤进行排查。这里我们先说明一下如何计算tp99:监控系统计算 TP99(第 99 百分位数的响应时间&…...
SpringBoot优雅关机,监听关机事件,docker配置
Spring Boot 提供了多种方法来实现优雅停机(Graceful Shutdown),这意味着在关闭应用程序之前,它会等待当前正在处理的请求完成,并且不再接受新的请求。 一、优雅停机的基本概念 优雅停机的主要步骤如下: …...
在【k8s】中部署Jenkins的实践指南
🐇明明跟你说过:个人主页 🏅个人专栏:《Kubernetes航线图:从船长到K8s掌舵者》 🏅 🔖行路有良友,便是天堂🔖 目录 一、引言 1、Jenkins简介 2、k8s简介 3、什么在…...
Unity DOTS从入门到精通之 C# Job System
文章目录 前言安装 DOTS 包C# 任务系统Mono 环境DOTS 环境运行作业NativeContainer 前言 作为 DOTS 教程,我们将创建一个旋转立方体的简单程序,并将传统的 Unity 设计转换为 DOTS 设计。 Unity 2022.3.52f1Entities 1.3.10 安装 DOTS 包 要安装 DOTS…...
Spring Boot 本地缓存工具类设计与实现
在 Spring Boot 应用中,缓存是提升性能的重要手段之一。为了更方便地使用缓存,我们可以设计一套通用的本地缓存工具类,封装常见的缓存操作,简化开发流程。本文将详细介绍如何设计并实现一套 Spring Boot 本地缓存工具类࿰…...
【Godot4.4】浅尝Godot中的MVC
概述 基于一个Unity的视频。学习了一下基本的MVC概念,并尝试在Godot中实现了一下。 原始的MVC: Godot中的MVC: Model、View和Controller各自应该实现的功能如下: Model: 属性(数据字段)数据存取方法数据更新信号 View: 控…...
如何解决前端的竞态问题
前端的竞态问题通常是指多个异步操作的响应顺序与发起顺序不一致,导致程序出现不可预测的结果。这种问题在分页、搜索、选项卡切换等场景中尤为常见。以下是几种常见的解决方法: 1. 取消过期请求 当用户发起新的请求时,取消之前的请求&…...
