前端(八)——深入探索前端框架中的Diff算法:优化视图更新与性能提升

在这里插入图片描述

😊博主:小猫娃来啦
😊文章核心:深入探索前端框架中的Diff算法:优化视图更新与性能提升

文章目录

  • 前端框架中的Diff算法概述
  • vue和react框架的diff算法
    • React的diff算法:
    • Vue的diff算法:
  • Diff算法在前端框架中的应用场景
  • 基本Diff算法原理及工作流程
    • 虚拟DOM的创建和更新
    • 节点比对和差异计算过程
  • 常见前端框架中的Diff算法实现
    • React框架的Reconciliation算法
    • Vue框架的响应式系统及Diff策略
  • 优化Diff算法的高级技巧
    • 键值对比和唯一标识符
    • 合并操作和批量处理
    • 异步渲染和增量更新
  • Diff算法的性能评估和优化方法
  • 参考文献

前端框架中的Diff算法概述

前端框架中的diff算法是一种比较两个虚拟DOM树之间差异的算法。在更新页面时,为了提高性能,前端框架通常会先生成新的虚拟DOM树,然后通过diff算法比较新旧虚拟DOM树的差异,并将差异应用到实际的DOM树上,以达到更新页面的目的。

diff算法的核心思想是尽量减少DOM操作次数,只对真正变化的部分进行更新,而不是全量替换整个DOM树。它通过深度优先遍历比较新旧虚拟DOM树中的节点,找出同一层级上不同的节点,并记录下它们的差异。

细分的话,diff算法可以分为以下几个步骤:

  • 比较两个节点是否相同,如果不相同,则认为该节点需要更新。
  • 如果两个节点类型不同,则直接替换节点。
  • 如果节点类型相同,比较节点的属性,更新发生变化的属性。
  • 对子节点进行递归比较,找出差异并更新。

在比较过程中,diff算法会基于一些启发式的策略来提高效率,例如使用唯一标识符(key)来帮助判断节点的移动和重排,从而减少不必要的DOM操作。

diff算法的核心是通过比较新旧虚拟DOM树之间的差异,只更新发生变化的部分,避免全量替换整个DOM树,从而提高页面的更新性能。

vue和react框架的diff算法

React和Vue是两个目前最流行的前端框架,它们都采用了不同的diff算法来实现高效的虚拟DOM更新。

React的diff算法:

React采用了一种称为"Reconciliation"的diff算法。它基于以下几个假设:

假设1:两个不同类型的组件会产生出不同的树形结构,它们的上下文也会完全不同。因此,React总是销毁旧的树,建立起新的树。
假设2:对于同一类型的组件,可以通过其props来判断是否需要重新渲染,即使其内部状态(state)发生了变化。
假设3:对于列表(数组)中的子元素,React会使用唯一的key标识每个元素,以便更准确地判断元素的增删和移动。

基于以上假设,React的diff算法可以简化为以下几个步骤:

步骤1:

比较两个节点的类型: 如果节点类型不同,直接替换该节点及其子树。 如果节点类型相同,进入下一步比较其属性。

步骤2:

比较节点的属性:更新发生变化的属性。

步骤3:

递归比较子节点:

  • 对子节点列表进行遍历,使用唯一的key来唯一标识每个子节点。
  • 在遍历过程中,React会尽量复用已存在的节点:
            如果新旧子节点列表中存在相同的key,会复用旧节点,并递归比较其属性和子节点。
            如果新旧子节点列表中不存在对应的key,会创建新节点并插入到对应位置。

React的diff算法采用了先序深度优先遍历的方式进行节点比较,通过标记(tag)来表示节点的操作类型,如插入、更新、移动、删除等。这样可以在遍历过程中尽早地找到差异,并将差异应用到实际的DOM树上,以最小的代价实现页面的更新。


Vue的diff算法:

Vue采用了一种称为"Virtual DOM with Keyed Diff"的diff算法。它也是基于虚拟DOM的比较和更新机制,但与React略有不同。

而Vue的diff算法呢主要包括以下几个步骤:

步骤1:

比较新旧虚拟DOM的根节点:

  • 如果节点类型不同,直接替换整个DOM树。
  • 如果节点类型相同,进入下一步。

步骤2:

逐层对比新旧虚拟DOM的子节点:

  • 首先,根据子节点的key进行查找和匹配。
  • 如果key匹配成功,说明是同一个节点,比较其属性并递归地对比其子节点。
  • 如果没有找到匹配的key,说明是新增的节点或者被移除的节点,进行插入或删除操作。

Vue的diff算法中,通过key来唯一标识每个子节点,以便更高效地判断节点的增删和移动。同时,Vue还使用了双端比较策略,在确定了匹配节点后,同时从新旧虚拟DOM的头尾进行对比,以提高性能。

值得注意的是,Vue的diff算法相对于React的算法而言,更加偏向于全量替换,即当节点类型相同但属性发生变化时,Vue会直接替换整个DOM节点,而不去细粒度地更新节点的属性。这是因为Vue更注重响应式数据的变化,而非手动操作的变化。


总结:
React的diff算法采用的是"Reconciliation"算法,通过先序深度优先遍历的方式逐层对比和更新差异。
Vue的diff算法采用的是"Virtual DOM with Keyed Diff"算法,通过key唯一标识子节点,并使用双端比较策略来提高性能。
那么React的useEffect这个hook的意义就出来了,关于vue,react,甚至微信小程序,uniapp的生命周期hooks,以及vue和react全面的区别,后续会出文章说明。

Diff算法在前端框架中的应用场景

Diff算法主要应用于对比新旧状态之间的差异,并针对变化进行局部更新。这种增量式的更新方式将减少不必要的DOM操作,提高页面性能和用户体验。

根据项目经验,以及对于前端框架的了解,我总结出了diff算法的4个应用场景。

首先是虚拟dom的更新

前端框架使用虚拟DOM(Virtual DOM)来表示页面结构,通过Diff算法比较新旧虚拟DOM树之间的差异,并将差异应用到实际的DOM上,从而实现页面的更新。这种方式减少了直接对实际DOM进行频繁的操作,提高了性能和效率。

其次是列表渲染的时候

当列表数据发生改变时,Diff算法可以精确找出新增、删除、移动或修改的列表项,并只更新发生变化的部分。这样可以避免重新渲染整个列表,减少不必要的工作量,提升性能。

表单输入方面

在表单输入的场景中,Diff算法可以监测用户的输入变化,并只更新与变化相关的部分。例如,当用户在输入框中键入文本时,Diff算法可以检测并更新输入框的值,而无需重新渲染整个表单。

动态切换组件的时候

在一些场景中,需要根据不同的条件或用户操作动态地切换组件的显示。Diff算法可以检测到组件的变化,并针对变化进行更新,使得只有需要变化的部分被重新渲染,提高页面响应速度。


基本Diff算法原理及工作流程

虚拟DOM的创建和更新

创建虚拟DOM:

  • 使用JSX或h()函数创建虚拟DOM元素:在前端框架中,通常使用JSX语法或h()函数来创建虚拟DOM元素。这些元素包含有关组件类型、属性、子节点等信息。

  • 构建虚拟DOM树:通过将创建的虚拟DOM元素以树的形式组织起来,形成虚拟DOM树。树的根节点表示整个页面结构,子节点表示嵌套的组件以及它们的子组件。

  • 将虚拟DOM树渲染为实际的DOM:通过遍历虚拟DOM树,并根据其中的节点类型、属性等信息,创建对应的实际DOM节点。最终,将创建的实际DOM插入到文档中展示给用户。

更新虚拟DOM:

  • 生成新的虚拟DOM树:当页面状态发生变化时,需要生成新的虚拟DOM树来反映这些变化。可以通过重新执行创建虚拟DOM的流程,生成与当前状态对应的新虚拟DOM树。

  • Diff算法比较新旧虚拟DOM树:使用Diff算法对比新旧虚拟DOM树之间的差异,找出需要更新的节点。

  • 生成DOM操作指令:根据Diff算法的结果,生成描述对实际DOM的操作指令,如添加、移动、修改或删除节点等。

  • 执行DOM操作:将生成的DOM操作指令应用于实际的DOM树,通过最小化操作的范围,高效地更新实际DOM,使其与新的虚拟DOM保持同步。

节点比对和差异计算过程

关于diff的原理,有太多博主都进行过文章讲解。我这里推荐一篇博客,我认为讲的是特别的清楚:
博主:疾风小蜗牛【vue】diff 算法详解

⭐⭐⭐其节点对比过程可以总结为5步:

  • 逐层比较节点类型:从根节点开始,逐级比较新旧虚拟DOM树中相同位置的节点类型(如标签名)是否相同。如果节点类型不同,说明节点已经完全不同,需要进行替换操作。

  • 比较节点属性:对于相同节点类型的节点,进一步比较它们的属性是否相同。如果属性有变化,需要执行更新操作。常见的属性包括样式、类名、事件监听器等。

  • 比较子节点:如果节点类型和属性都相同,接下来需要比较它们的子节点。这里使用递归的方式,将子节点进行同样的节点比对和差异计算过程。对于子节点的处理也包括插入、移动、更新、删除等操作。

  • 生成差异计算结果:在比对过程中,记录所有的节点差异情况,包括新增节点、删除节点、属性变化、移动节点等。这些差异计算结果通常以一种数据结构(如数组、对象等)的形式保存。

  • 应用差异计算结果:根据差异计算结果,执行相应的操作指令,将差异应用到实际的DOM上。这可以通过使用DOM操作API实现,如createElement()、appendChild()、removeChild()等

常见前端框架中的Diff算法实现

React框架的Reconciliation算法

React框架中的调和(Reconciliation)算法是用来比较新旧虚拟DOM树之间的差异,并将变化应用到实际的DOM上的一种算法。以下是React中调和算法的基本原理:

  1. Diff策略:React使用了一种称为"diffing"的算法来比较两棵虚拟DOM树的差异。比较过程从根节点开始,逐层向下进行。

  2. 唯一标识:在比较过程中,React要求每个可渲染的元素都需要有唯一的"key"属性,用于辅助React判断哪些元素需要更新或删除。

  3. 比较节点类型:React首先会比较新旧虚拟DOM树中相同位置的节点的类型(如标签名)是否相同。如果节点类型不同,React会直接销毁旧节点,并创建新节点。

  4. 比较节点属性:对于相同节点类型的节点,React会比较它们的属性是否相同。只有属性值不同的属性才会触发更新操作。

  5. 递归比较子节点:如果节点类型和属性都相同,React会递归地比较它们的子节点。React会尽可能复用已存在的节点,最小化对实际DOM的操作。

  6. 列表渲染:当遇到列表渲染时,React会使用key属性来辨别列表中的每个元素。如果在新旧虚拟DOM树中某个位置的节点类型发生变化,React会销毁旧节点并创建新节点。但是,如果两棵树中相同位置的节点类型相同,React会尽可能地复用节点,只对属性发生变化的节点进行更新。

通过调和算法,React能够高效地比较新旧虚拟DOM树之间的差异,并最小化实际DOM操作的次数,提高性能和效率。需要注意的是,React的调和算法是基于启发式的策略,并不是一个绝对的最优解,所以在特定的场景下可能会存在一些性能瓶颈。

Vue框架的响应式系统及Diff策略

Vue框架的响应式系统和Diff策略是Vue实现数据驱动视图更新的核心机制。下面将对Vue的响应式系统和Diff策略进行一个深入的研究,通过三个层面来论述:

响应式系统:

  • Object.defineProperty与Proxy:Vue通过Object.defineProperty或ES6的Proxy来拦截对数据对象的访问和修改,实现数据的响应式。这些拦截器能够捕获数据的读取和修改操作,并通知相关的依赖进行更新。
  • 依赖收集:在Vue的响应式系统中,有一个依赖收集的过程。在模板中使用的数据属性(getter)会被收集为依赖,当数据发生变化时,依赖会被通知,进而触发更新。
  • Watcher与Dep:Watcher是一个观察者,它订阅多个依赖,当依赖发生变化时,Watcher会被通知执行相应的回调函数。而Dep则是一个依赖管理器,用于维护依赖与Watcher之间的关系。

Diff策略:

  • 虚拟DOM树:Vue使用虚拟DOM来表示真实的DOM结构,这是一棵轻量级的JavaScript对象树。在每次视图更新时,Vue会重新生成一颗新的虚拟DOM树。
  • Diff算法:Vue的Diff算法通过比较新旧虚拟DOM树的差异,找出需要变更的部分,并生成最小的DOM操作。Vue使用了一种高效的双指针的Diff算法,以减少比较的复杂度。
  • Diff过程:
          标记阶段:Vue会对新旧虚拟DOM树的节点进行标记,标记为静态节点、同一个类型的节点或不同类型的节点。
          对比阶段:Vue从新旧虚拟DOM树的两端开始,使用双指针进行节点比较,根据节点类型和Key来判断节点的差异,并记录差异。
          更新阶段:根据Diff过程中记录的差异,对实际的DOM进行相应的增、删、改操作。

优化策略:

  • 列表渲染优化:在列表渲染时,Vue会使用每个节点的Key属性来判断节点的稳定性,从而尽可能地复用已存在的DOM元素,减少DOM操作次数。
  • 异步更新:为了提高性能,Vue对多次数据改变进行批量异步更新,将视图更新操作收集起来,在下一个事件循环执行统一的DOM操作,避免频繁的DOM修改。

优化Diff算法的高级技巧

键值对比和唯一标识符

⭐⭐⭐键值对比:
假设有两个对象,表示学生信息,其中键是学生的ID,值是学生的姓名。通过比较键的值,我们可以判断两个对象是否表示同一个学生:

const student1 = { id: 1, name: 'Alice' };
const student2 = { id: 2, name: 'Bob' };// 键值对比较
console.log(student1.id === student2.id); // false

在Vue的Diff算法中,我们可以使用Key属性来判断节点是否相同。例如,在Vue的模板中循环渲染学生列表时,可以将学生的ID作为Key值:

<template><ul><li v-for="student in students" :key="student.id">{{ student.name }}</li></ul>
</template>

这样做可以确保当学生列表发生变化时,Vue可以通过Key值判断哪些节点是相同的,从而只更新需要更改的节点。

⭐⭐⭐唯一标识符:
在前端开发中,唯一标识符经常用于定位和操作DOM元素。例如,假设我们有一个按钮组件,每个按钮都具有唯一的标识符,我们可以使用该标识符在点击按钮时执行相应的操作:

<template><div><button v-for="button in buttons" :id="button.id" @click="handleClick(button.id)">{{ button.label }}</button></div>
</template><script>
export default {data() {return {buttons: [{ id: 1, label: 'Button 1' },{ id: 2, label: 'Button 2' },{ id: 3, label: 'Button 3' }]};},methods: {handleClick(id) {console.log('Button clicked:', id);// 执行相应的操作}}
};
</script>

每个按钮都具有唯一的ID标识符,当点击按钮时,根据唯一标识符执行相应的操作。

合并操作和批量处理

合并操作和批量处理可以在某些场景下提高效率和性能。

假设我们有一个电商平台,需要将多个订单的总金额进行计算,并发送给用户。假设订单数据存储在一个数组中,每个订单对象包含订单ID和订单金额。

const orders = [{ id: 1, amount: 100 },{ id: 2, amount: 200 },{ id: 3, amount: 150 },// 更多订单...
];

我们可以使用合并操作和批量处理来优化计算过程。首先,我们定义一个变量来存储总金额:

let totalAmount = 0;

然后,我们遍历订单数组,并将每个订单的金额累加到总金额变量中:

orders.forEach(order => {totalAmount += order.amount;
});

这种方法是逐个遍历订单,逐个累加金额。但如果订单数量非常大,这样的处理方式可能会导致性能问题。

为了提高效率,我们可以使用合并操作和批量处理。我们首先将订单数组拆分成多个批次,每个批次包含一定数量的订单。然后,我们可以使用并行处理来同时对每个批次进行金额累加。

const batchSize = 100; // 设置每个批次的订单数量
const numBatches = Math.ceil(orders.length / batchSize); // 计算需要的批次数// 使用并行处理处理每个批次
for (let i = 0; i < numBatches; i++) {const batch = orders.slice(i * batchSize, (i + 1) * batchSize);// 使用合并操作对批次中的订单金额进行累加const batchTotal = batch.reduce((acc, order) => acc + order.amount, 0);// 更新总金额totalAmount += batchTotal;
}

通过将订单数组分割成多个批次,并使用并行处理对每个批次进行金额累加,我们可以同时处理多个订单,从而提高计算效率。

上面例子中,合并操作和批量处理结合起来,帮助我们更高效地处理大量数据。这种方法在数据处理、并行计算等场景下非常实用,能够极大地提升程序的性能和响应速度。

异步渲染和增量更新

异步渲染和增量更新是两种提高前端性能和用户体验的技术。

异步渲染:
异步渲染指的是将页面渲染过程分解成多个步骤,在每个步骤之间插入浏览器空闲时间,以便让其他任务优先执行。这样可以防止长时间运行的任务阻塞页面响应。常见的异步渲染技术包括:

  • 虚拟DOM:使用虚拟DOM可以将视图的更新操作延迟到下一个事件循环中进行,从而避免频繁的重绘和回流操作。
  • Web Worker:将一些计算密集型的任务放在Web Worker中执行,使得主线程可以同时处理用户交互和渲染更新。
  • 请求动画帧(requestAnimationFrame):使用requestAnimationFrame方法来安排页面更新操作,以便在下一次浏览器重绘之前执行。

通过异步渲染,我们可以提高页面的响应速度,减少卡顿和阻塞现象,从而改善用户体验。

增量更新:
增量更新是一种以增量方式更新页面的技术,只对发生变化的部分进行更新,而不是重新渲染整个页面。这可以减少不必要的计算和DOM操作,提高更新的效率。常见的增量更新技术包括:

  • 虚拟DOM Diff算法:使用虚拟DOM来比较前后两次渲染结果的差异,并只更新发生变化的部分,而不是重新渲染整个页面。
  • UI状态管理:使用状态管理库(如React的Redux、Vue的Vuex等)来实现组件级别的状态管理和更新控制,按需更新特定组件或子树。
  • 懒加载和无限滚动:延迟加载页面的内容或仅在需要时加载,以避免一次性加载大量数据或资源。

通过增量更新,我们可以最小化页面的重绘和回流操作,减少不必要的开销,提高页面更新的效率和性能。


Diff算法的性能评估和优化方法

我们从从三个角度去优化

角度1:内存消耗和时间复杂度分析

  • 内存消耗分析:了解算法在不同输入规模下所需的内存消耗情况非常重要。可以使用内存分析工具或者监控内存占用来获取准确的内存使用数据。比较长字符串或大文件时,需要特别关注内存消耗是否会超出系统的限制。
  • 时间复杂度分析:通过对算法执行过程中每个步骤的时间复杂度进行分析,可以得出算法的总体时间复杂度。这有助于评估算法的执行效率和性能。一般情况下,我们关注最坏情况下的时间复杂度,其表示了算法执行所需的最大时间。

角度2:虚拟DOM重排和重绘优化:

  • 虚拟DOM:虚拟DOM是一种与实际DOM树相对应的轻量级对象树,用于描述页面的结构。Diff算法通常用于比较两个虚拟DOM树之间的差异,以便更新实际的DOM树。为了优化性能,可以采取以下策略:
  • 合并操作:将多个DOM更新操作合并为一个批处理操作,减少引起重排和重绘的次数。
  • 批处理更新:通过使用requestAnimationFrame等机制,将多个DOM更新操作放入单个渲染帧中,以避免多次重排和重绘。
  • 避免频繁修改样式:频繁修改元素的样式属性会导致浏览器强制进行重排和重绘。可以使用CSS类名的切换或者直接修改样式表来一次性应用样式。

角度3:状态持久化和缓存策略:

  • 状态持久化:对于需要频繁进行Diff操作的场景,可以将Diff结果进行持久化。即将Diff的结果保存下来,以便后续对相同或相似的输入进行比较时,可以直接使用已有的结果。这样可以避免重复计算,提高性能。持久化的形式可以是内存中的缓存,也可以是存储在数据库或文件系统中。
  • 缓存策略:缓存是一种常见的性能优化方案。可以根据具体需求选择合适的缓存策略,如LRU(最近最少使用)或LFU(最不常用)。通过缓存Diff的结果,可以避免重复执行完整的Diff操作。当需要比较相似的输入时,可以首先检查缓存,如果存在相应的结果,则直接使用缓存中的比较结果。

参考文献

  • vue源码解析之diff原理
  • Vue 的 diff 算法解析
  • 面试官:说说vue的diff算法
  • 详解三种 Diff 算法(源码+图)
  • c知道
  • Diff算法
  • DIFF算法原理
  • 重学Vue【组件更新和diff算法】
  • 【vue】diff 算法详解

在这里插入图片描述


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/5391.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于深度学习的高精度课堂人脸检测系统(PyTorch+Pyside6+YOLOv5模型)

摘要&#xff1a;基于深度学习的高精度课堂人脸检测系统可用于日常生活中或野外来检测与定位课堂人脸目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的课堂人脸目标检测识别&#xff0c;另外支持结果可视化与图片或视频检测结果的导出。本系统采用YOLOv5目标…

C# 未提供必须形参对应的实参

这个问题是在写观察者模式中遇到的一个问题。 具体的代码可以到《设计模式&#xff08;十五&#xff09;之观察者模式》中下载&#xff0c;下边只是部分代码。 我在抽象类中定义了构造函数&#xff0c;代码如下&#xff1a; using System; using System.Collections.Generic;…

设计模式-享元模式在Java中的使用示例-围棋软件

场景 享元模式 简介 当一个软件系统在运行时产生的对象数量太多&#xff0c;将导致运行代价过高&#xff0c;带来系统性能下降等问题。 例如在一个文本字符串中存在很多重复的字符&#xff0c;如果每一个字符都用一个单独的对象来表示&#xff0c;将会占用 较多的内存空间…

【案例教程】基于Python机器学习、深度学习技术提升气象、海洋、水文领域实践应用能力

Python是功能强大、免费、开源&#xff0c;实现面向对象的编程语言&#xff0c;能够在不同操作系统和平台使用&#xff0c;简洁的语法和解释性语言使其成为理想的脚本语言。除了标准库&#xff0c;还有丰富的第三方库&#xff0c;Python在数据处理、科学计算、数学建模、数据挖…

Vue中值的传递(父传子,子传父,子父同步)

1.父组件->子组件传递数据 ①父组件通过 v-bind: 属性绑定的形式&#xff0c;把数据传递给子组件 如果不需要动态绑定&#xff0c;则可以直接写number“张三” ②子组件中&#xff0c;通过props接收父组件传递过来的数据 2.子组件->父组件传递数据 1.在子组件中&#xf…

实现外部缓存-Redis

目录 实现 RedisTemplate RedisTemplate的序列化 RedisSerializer 创建Redis缓存配置类 测试使用 创建配置类 创建注解测试实体 创建配置文件 创建单元测试类进行测试 实现 RedisTemplate XXXTemplate 是 Spring 的一大设计特色&#xff0c;其中&#xff0c;RedisTe…

【基础算法】——双指针算法

文章目录 一、算法原理二、算法实战1. 力扣283 移动零2. 力扣1089 复写零3. 力扣15 三数之和4. 力扣18 四数之和 三、总结 一、算法原理 双指针算法是指在遍历对象的过程中不是普通的使用单个指针进行访问&#xff0c;而是使用两个相同方向(快慢指针)或者相反方向&#xff08;…

Tomcat服务器下载安装及配置教程(IDEA中使用Tomcat)

目录 友情提醒第一章、Tomcat下载与安装1.1&#xff09;Tomcat介绍1.2&#xff09;官网下载 第二章、Tomcat配置环境变量2.1&#xff09;windows环境变量配置2.2&#xff09;验证Tomcat配置是否成功2.3&#xff09;报错解决 第三章、IDEA整合Tomcat3.1&#xff09;打开IDEA开发…

【深度学习笔记】随机梯度下降法

本专栏是网易云课堂人工智能课程《神经网络与深度学习》的学习笔记&#xff0c;视频由网易云课堂与 deeplearning.ai 联合出品&#xff0c;主讲人是吴恩达 Andrew Ng 教授。感兴趣的网友可以观看网易云课堂的视频进行深入学习&#xff0c;视频的链接如下&#xff1a; 神经网络和…

springboot项目创建整个完成过程和注意事项

1&#xff1a;application.yml文件配置 server:port: 8088servlet:context-path: /test spring:datasource:name: text #????url: jdbc:mysql://localhost:3306/dsdd?serverTimezoneGMT&useUnicodetrue&characterEncodingutf-8&useSSLtrueusername: root #…

Rust 数据类型 之 结构体(Struct)

目录 结构体&#xff08;Struct&#xff09; 定义与声明 结构体定义 结构体实例 结构体分类 单元结构体&#xff08;Unit Struct&#xff09; 元组结构体&#xff08;Tuple Struct&#xff09; 具名结构体&#xff08;Named Struct&#xff09; 结构体嵌套 结构体方法…

【后端面经】前言汇总(0)

文章目录 一、机会是留给有准备的人二、课程设计第一部分:微服务架构第二部分:数据库与 MySQL第三部分:消息队列第四部分:缓存所谓缓存用得好,性能没烦恼。第五部分:NoSQL三、总结一、机会是留给有准备的人 近两年互联网行业增速放缓,ChatGPT 又引发了一波新的 AI 浪潮,…

使用ffmpeg合并视频遇到的坑

下面以Linux环境介绍为主 1.ffmpeg可执行命令不同的环境是不同的&#xff0c;Linux在执行命令前还需要授权。 2.合并视频命令&#xff1a; 主要命令: {} -f concat -auto_convert 0 -safe 0 -i {} -y -c:v copy 坑一&#xff1a;其中第一个花括号替换的是可执行命令所在的…

【GitOps系列】使用Kustomize和Helm定义应用配置

文章目录 使用 Kustomize 定义应用改造示例应用1.创建基准和多环境目录2.环境差异分析3.为 Base 目录创建通用 Manifest4.为开发环境目录创建差异 Manifest5.为预发布环境创建差异 Manifest6.为生产环境创建差异 Manifest 部署 Kustomize 应用部署到开发环境部署到生产环境 使用…

OpenCv (C++) 使用矩形 Rect 覆盖图像中某个区域

文章目录 1. 使用矩形将图像中某个区域置为黑色2. cv::Rect 类介绍 1. 使用矩形将图像中某个区域置为黑色 推荐参考博客&#xff1a;OpenCV实现将任意形状ROI区域置黑&#xff08;多边形区域置黑&#xff09; 比较常用的是使用 Rect 矩形实现该功能&#xff0c;代码如下&…

打造i-SMART智能网联平台,亚马逊云科技助力上汽快速出海

当前在各大外资车企不断加码在华投资之际&#xff0c;越来越多的中国汽车品牌纷纷开始走出国门&#xff0c;加速推进全球化业务&#xff0c;将赛道转至更为广阔的海外市场。 上汽海外出行科技有限公司&#xff08;简称“上汽海外出行”&#xff09;成立于2018年&#xff0c;承…

linux高并发web服务器开发(web服务器)18_函数解析http请求, 正则表达式,sscanf使用,http中数据特殊字符编码解码

pdf详情版 01 学习目标 编写函数解析http请求 ○ GET /hello.html HTTP/1.1\r\n ○ 将上述字符串分为三部分解析出来编写函数根据文件后缀&#xff0c;返回对应的文件类型sscanf - 读取格式化的字符串中的数据 ○ 使用正则表达式拆分 ○ [^ ]的用法通过浏览器请求目录数据 ○…

【unity之IMGUI实践】单例模式管理数据存储【二】

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;uni…

每日一题——迷宫问题(I)

迷宫问题——I 题目链接 思路 创建二维数组&#xff0c;并实现输入 首先输入二维数组的行和列&#xff1a; int n, m; scanf("%d%d", &n, &m);然后动态开辟二维数组&#xff1a; 注&#xff1a;对动态开辟还不太了解的同学可以看看&#x1f449;C语言—…

CPU密集型和IO密集型任务的权衡:如何找到最佳平衡点

关于作者&#xff1a;CSDN内容合伙人、技术专家&#xff0c; 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 &#xff0c;擅长java后端、移动开发、人工智能等&#xff0c;希望大家多多支持。 目录 一、导读二、概览三、CPU密集型与IO密集型3.1、CPU密集型3.2、I/O密…