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

news2024/11/26 13:50:55

在这里插入图片描述

😊博主:小猫娃来啦
😊文章核心:深入探索前端框架中的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.coloradmin.cn/o/780592.html

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

相关文章

实训笔记7.20

实训笔记7.20 7.20一、座右铭二、HDFS宕机之后的副本数的问题三、MapReduce的工作流程&#xff08;简单版本&#xff09;四、Hadoop的序列化问题五、MR程序运行中InputFormat类的作用5.1 作用主要有两个5.2 有一个核心实现类--抽象类FileInputFormat 当输入的数据是文件的时候5…

【图像分类】基于LIME的CNN 图像分类研究(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f308;4 Matlab代码实现 &#x1f4a5;1 概述 基于LIME&#xff08;Local Interpretable Model-Agnostic Explanations&#xff09;的CNN图像分类研究是一种用于解释CNN模型的方法。LIME是一…

实用的设计模式08——适配器模式

适配器的单词是Adapter&#xff0c;我们在开发时经常碰到叫做XxxAdapter的类&#xff0c;此时一般就是使用了适配器模式&#xff0c;适配器模式是非常常用&#xff0c;本文就对适配器模式做一个简单的介绍 文章目录 1、真实开发场景的问题引入2、适配器模式讲解2.1 核心类及类图…

2021年全国大学生电子设计竞赛H题——用电器分析识别装置

用电器分析识别装置 一、题目要求二、系统方案三、硬件设计3.1、ATT7022电参数采集模块 一、题目要求 任务 设计并制作一个根据电源线电流的电参量信息分析在用电器类别的装置。该装置具有学习和分析识别两种工作模式。在学习模式下&#xff0c;测试并存储用于识别各单件电器的…

百亿规模京东实时浏览记录系统的设计与实现 | 京东云技术团队

1. 系统介绍 浏览记录系统主要用来记录京东用户的实时浏览记录&#xff0c;并提供实时查询浏览数据的功能。在线用户访问一次商品详情页&#xff0c;浏览记录系统就会记录用户的一条浏览数据&#xff0c;并针对该浏览数据进行商品维度去重等一系列处理并存储。然后用户可以通过…

mybatis事物是如何和spring事物整合的

目录 1、mybatis事物管理器 2、SpringManagedTransactionFactory如何处理事物 3、spring事物如何设置connection连接到threadLocal 1、mybatis事物管理器 mybatis事物抽象接口类&#xff1a;Transaction。该接口定义了事物基本方法和获取数据库连接方法 该类有三个实现类Jd…

【本地开发快速添加localstoreage和cookie】

在本地开发时&#xff0c;通常会需要线上开发或测试环境的缓存&#xff0c;然而&#xff0c;如果缓存过多时&#xff0c;一个一个的复制key&#xff0c;value太过麻烦&#xff0c;于是本文介绍了一种快速设置缓存的方法。 cookie 需要用到插件&#xff0c;使用JSON格式导出&am…

PPT逻辑设计与完美呈现

PPT逻辑设计与完美呈现 https://haoxinyunxueyuan.zhixueyun.com/#/study/course/detail/detailInfoCD00——朱宁川 logo设计神器: https://www.zitijia.com/logodiy/index 一 PPT设计 第一章、PPT的灵魂设计-5W PPT灵魂设计(5W) 以终为始&#xff0c;从目标出发 why 目…

136. 只出现一次的数字

题目 题解一&#xff1a;采用map集合 class Solution {public static int singleNumber(int[] nums) {Map map new HashMap<Integer,Integer>();for (int i 0; i < nums.length; i) {//判断key是否重复&#xff0c;重复直接删掉重复的keyif (map.containsKey(nums[i…

JavaWeb 速通Servlet(请求转发和请求重定向)

目录 一、HttpServletRequest 1.简介 : 2.常用方法 : 1 getRequestURI() : 2 getRequestURL() : 3 getRemoteHost() : 4 getHeader(String header) : 5 getParameter(name) : 6 getParameterValues(name) : 7 getMethod() : 8 setAttribute(key, value) : 9 getAttrib…

面试之JVM的储存空间

Java8之后&#xff0c;取消了整个永久代区域&#xff0c;取而代之的是元空间。运行时常量池和静态常量池存放在元空间中&#xff0c;而字符串常量池依然存放在堆中。&#xff08;&#xff09; JVM允许时数据区 程序计数器的特点以及作用 &#xff1f; 1、程序计数器 是一块较…

protobuf学习

protobuf的安装 Windos版安装 下载地址&#xff1a;https://github.com/protocolbuffers/protobuf/releases 选择合适的版本下载 将下载的压缩包解压&#xff0c;把解压后文件的bin目录的路径配置到系统环境比变量Path中 在cmd 中执行 protoc --version 成功就说明安装成功了l…

Vue.js基础简答题

系列文章目录 后续补充 文章目录 系列文章目录前言一、库与框架的区别是什么&#xff1f;二、Vue.js 的核心特性有哪些&#xff1f;三、什么是数据驱动视图&#xff1f;四、MVVM 模型各部分含义是什么&#xff0c;在 Vue.js 中分别对应哪些功能&#xff1f;五、el 选项的作用是…

一)Stable Diffusion使用教程:安装

目前AI绘画最火的当属Midjorney和Stable Diffusion&#xff0c;但是由于Midjourney没有开源&#xff0c;因此我们主要分享下Stable Diffusion&#xff0c;后面有望补上Midjourney教程。 本节主要讲解Stable Diffusion&#xff08;以下简述SD&#xff09;的下载和安装。 1&…

uniapp查看ios打包后的Info.plist文件

最近在用 uni 开发 ios 的时候给项目添加了自定义的 Info.plist 文件&#xff0c;但是打包后发现并没有生效&#xff0c;才有了查看打包后的 Info.plist 文件想法。 HBuilderX3.6.5起&#xff0c;支持直接在应用项目中配置 iOS 平台的 Info.plist 和 资源文件&#xff08;Bundl…

pytest中生成allure报告时,测试报告中统计的用例数不正确

【问题描述】&#xff1a;pytest中生成allure报告时&#xff0c;测试报告中统计的用例数不正确&#xff0c;用例数总是比实际用例数多 【问题定位】&#xff1a;因为生成index.html的allure报告&#xff0c;是根据临时的json文件生成的。每次运行时&#xff0c;没有删除旧的js…

Grafana图形web监控的安装与配置

目录 一、安装并配置 二、Web访问 三、Grafana启用zabbix插件 四、Grafana添加zabbix数据源 五、创建仪表盘 创建监控项完成保存仪表盘 六、查看创建的仪表盘 七、在现有的dashboard&#xff08;仪表盘&#xff09;中添加图形 八、查看最终dashborad&#xff08;仪表盘&#x…

react 实现小球加入购物车动画

代码 import React, { useRef } from react;const ProductLayout () > {const box useRef(null);const createBall (left, top) > {const ball document.createElement(div);ball.style.position absolute;ball.style.left left - 10 px;ball.style.top top - 1…

三维点云中的坐标变换(只讲关键部分)

一、坐标旋转 坐标旋转包含绕x、y、z轴旋转&#xff0c;在右手坐标系中&#xff0c;x-翻滚(roll)&#xff0c;y-俯仰(pitch)&#xff0c;z-航向(yaw)。如果想详细了解&#xff0c;可以网络搜索 在PCL中&#xff0c;从baseLink到map的转换关系为:先绕x轴旋转,在绕y轴旋转,最后绕…

linux:secureCRT通过pem证书远程访问服务器

参考&#xff1a; secureCRT通过pem证书远程访问服务器_Fengshana的博客-CSDN博客 总结&#xff1a; 配置公钥即可