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

Vue开发中常见优化手段总结

Tree Shaking or Trunk

动态引入(Dynamic Imports)
动态引入是指在代码执行过程中,根据需要动态加载模块,而不是在应用启动时一次性加载所有模块。这可以通过JavaScript的import()函数实现,它返回一个Promise对象,允许你异步加载模块。

在Vue中,你可以在组件中使用动态引入来按需加载组件或模块。例如:

// 动态引入一个Vue组件
const MyComponent = () => import('./MyComponent.vue');export default {components: {MyComponent}
}

在这个例子中,MyComponent组件不会在应用启动时加载,而是在实际需要渲染这个组件的时候才加载。

按需加载(On-Demand Loading)

按需加载是指根据用户的交互或应用的状态来加载资源,这样可以减少应用的初始加载时间,提高用户体验。在Vue应用中,按需加载通常与路由和组件结合使用。

Vue Router支持按需加载,你可以在路由配置中使用动态引入来实现:

const routes = [{path: '/about',component: () => import('./views/AboutView.vue')},{path: '/contact',component: () => import('./views/ContactView.vue')}
];

import AppView from '../views/AppView.vue'const gender = 'man'// Commonjs 相对于 EsModule 的区别?
// tree-shaking 一定要使用 EsModule
// if (gender === 'man') {
//   require('../views/DataSourceContent/DataSourceContent.vue')
// } else {
//   require('../views/DataSourceView.vue')
// }// chunk
if (gender === 'man') {// 实现分片// 动态加载import('../views/DataSourceContent/DataSourceContent.vue')
} else {// 动态加载import('../views/DataSourceView.vue')
}// 从 URL 输入到页面展示,这个过程中发生了什么?const router = createRouter({history: createWebHistory(import.meta.env.BASE_URL),routes: [],build: {rollupOptions: {
+      treeshake: true,
+      plugins: [
+        // rollupPluginVue(),
+      ],output: {
-        manualChunks: {
-          'vue-common-lib': ['vue', 'vue-router', 'pinia'],
-          'react-common-lib': ['react', 'react-dom', '@glideapps/glide-data-grid'],
+        // manualChunks: {
+        //   'vue-common-lib': ['vue', 'vue-router', 'pinia'],
+        //   'react-common-lib': ['react', 'react-dom', '@glideapps/glide-data-grid'],
+        // }
+        manualChunks(id, { getModuleIds, getModuleInfo }) {
+          console.log('🚀 ~ manualChunks ~ getModuleInfo:', id, getModuleIds(), getModuleInfo(id))
+          const deps = []
+          const depSubDepId = new Set()
+          if (id.includes('node_modules')) {
+            if (id.includes('vue')) {
+              return 'vue-common-lib'
+            }
+            if (id.includes('react')) {
+              return 'react-common-lib'
+            }
+          }}}}

动态引入与按需加载的协同工作
动态引入和按需加载可以协同工作,以优化应用的性能和用户体验。通过动态引入,你可以将大型应用拆分成更小的代码块,然后根据用户的行为(如点击不同的路由)按需加载这些代码块。

这种方式的好处包括:

  • 减少初始加载时间:用户在加载应用时不必等待所有代码都加载完成。
  • 节省带宽:用户只下载他们实际需要的代码。
  • 提高缓存效率:浏览器可以更有效地缓存按需加载的代码块。

常见性能分析手段

  • rollup-plugin-visualizer 分析构建
  • vue devtools,google 插件,rerender 进行分析
  • performance
  • lighthouse
  • memory

打包分Trunk

针对 vite 进行配置

import { defineConfig, splitVendorChunkPlugin } from 'vite'plugins: [// vue(),// vueJsx(),splitVendorChunkPlugin(),
]build: {rollupOptions: {output: {manualChunks: {'vue-common-lib': ['vue', 'vue-router', 'pinia'],'react-common-lib': ['react', 'react-dom', '@glideapps/glide-data-grid'],}}}},

前后对比

在这里插入图片描述

在这里插入图片描述
按需加载组件

// vue router 配置{path: 'layout',name: 'layout',component: () => defineAsyncComponent(() => import('../views/PageLayoutView.vue'))},

Vue Tools

主要分析 vue 项目有没有频繁的 rerender
假设我们项目中有一个数据是数组类型,在发生数据更新时,我们直接重写整个数组数据,这样会导致整个与数据相关联的组件全部重新渲染

为什么要给元素加 key,就是为了辅助 diff 的过程
vue2:全量 diff,key 来去告知 vue 你的组件更新前后节点发生了什么变化,一旦你的数据全量发生了变化(数组变成了新数组,对象变成了新对象【对象引用地址完全变化了】)
vue3:简单 diff、快速 diff、双端 diff

在Vue中,v-for 指令用于基于源数据多次渲染元素或模板块。在使用 v-for 时,key 是一个非常重要的属性,它的作用主要有以下几点:

提高渲染效率:
Vue在更新动态列表时,使用 key 属性可以帮助Vue精确识别每个节点的身份,从而重用和重新排序现有元素,而不是重新创建所有元素。这可以提高渲染效率,特别是在列表数据频繁变化的场景下。

避免组件/元素的重复渲染:
如果列表中的项目顺序可能会改变,或者项目会动态添加或删除,使用 key 可以确保每个项目有一个独一无二的标识符,Vue可以根据这个标识符决定是否重新渲染组件。

维护组件状态:
在列表中使用组件时,如果子组件有自己的状态,并且这个状态需要在列表更新时保持不变,那么 key 就非常重要。没有 key,Vue可能会错误地复用组件实例,导致组件状态的丢失。

提供唯一的DOM引用:
当你需要通过DOM操作或者事件处理器访问列表中的特定元素时,key 可以帮助Vue为每个元素提供唯一的引用。

避免潜在的bug:
没有 key,Vue在处理列表更新时可能会遇到一些难以追踪的bug,比如元素状态的意外变化或者渲染不正确。

Vue 常见分析思路

通常,针对 Vue3 项目,我们需要考虑较好性能,就需要分析应用性能瓶颈,从而针对渲染与部分逻辑实现,进行改良优化。比如:

  1. 虚拟列表,virtualList https://github.com/tangbc/vue-virtual-scroll-list
  2. 异步组件结合 chunk
  3. canvas 在大数据量内容渲染下的应用
  4. 减少 rerender,分析 props、state
  5. 使用 provide、inject
  6. 解决 vue 组件 props 层层传递的问题,而这个传递过程中,有些组件其实压根儿没有用到对应的 props,他只是起到一个传递的作用,以此性能也受到了牵连
// 针对 Vue2 的同学
// parent component providing 'foo'
var Provider = {provide: {foo: 'bar'},// ...
}// child component injecting 'foo'
var Child = {inject: ['foo'],created () {console.log(this.foo) // => "bar"}// ...
}
provide('editable', false)// 在需要使用的组件中
inject('editable')
  1. 动态组件合理使用 KeepAlive
  2. 事件清除
  3. 计时器清除,防止内存泄漏
  4. lodash-es 比 lodash 更好

分析包体积
一般的优化思路
10. 分包,chunk
11. asyncComponent,异步导入,动态加载
12. ssr

Keep-alive使用

<LaptopPreviewerv-if="previewMode === 'laptop'":key="'laptop'":preview-mode="previewMode"@preview-mode-change="handleModeChange"
/>
<MobilePreviewerv-if="previewMode === 'mobile'":key="'mobile'":preview-mode="previewMode"@preview-mode-change="handleModeChange"
/>

可以修改为

    <KeepAlive><component:is="previewMode === 'laptop' ? LaptopPreviewer : MobilePreviewer":preview-mode="previewMode"@preview-mode-change="handleModeChange"/></KeepAlive>

Note:

  • **合理使用:**keep-alive通过缓存已经渲染的组件来提升应用性能,但过多使用可能会导致内存占用增加,因此需要谨慎使用。只在真正需要保持组件状态的场景下使用keep-alive

  • **控制缓存的组件数量:**默认情况下,keep-alive会缓存所有经过它的子组件。如果不需要缓存所有组件,可以通过include和exclude属性来选择性地缓存组件,以避免不必要的内存占用

  • **生命周期的影响:**被keep-alive缓存的组件,会在activated和deactivated生命周期钩子函数中触发相应的逻辑。因此,在使用keep-alive时,要注意这些生命周期函数的使用场景和影响

  • 组件状态更新:由于keep-alive组件对缓存的组件进行了复用,需要小心处理组件状态的更新。一些状态变更操作可能不会在组件重新激活时触发,需要手动处理相应的逻辑

  • **样式与动画:**由于keep-alive会复用组件实例,可能会导致一些样式和动画的问题,特别是涉及到组件之间的切换效果时,需要特别注意相关的样式和动画逻辑

  • **避免内存泄漏:**使用keep-alive时需要注意避免内存泄漏。确保正确配置include和exclude属性,以避免缓存不需要的组件。只缓存需要保留状态的组件,避免缓存不需要的组件导致内存泄漏

  • 动态配置:根据不同的应用场景和用户需求,动态配置include和exclude属性。例如,根据用户的登录状态或访问的页面,动态调整需要缓存的组件

  • **及时清理缓存:**当不再需要缓存某个组件时,及时清理缓存。可以使用v-if或v-show等指令来控制keep-alive的显示和隐藏,以释放不需要的缓存

  • **多层嵌套路由缓存问题:**在多层嵌套路由中,可以通过将所有router-view都通过keep-alive包裹起来,并使用include或exclude属性来判断是否需要缓存

  • 动态组件缓存问题:如果多个路由使用同一个组件,可以通过动态修改组件的名称来解决缓存问题,确保每个路由的组件实例都有唯一的名称,从而正确缓存

事件清除

const resize = () => {const isMobile = isMobileTablet()if (isMobile) {device.value = 'mobile'} else {device.value = 'laptop'}
}onMounted(() => {const isMobile = isMobileTablet()if (isMobile) {device.value = 'mobile'}window.addEventListener('resize', resize, false)
})onUnmounted(() => {window.removeEventListener('resize', resize, false)
})

定时器清除

let timer: number | null = nullonMounted(() => {// 注意,一定要使用 window.setInterval,否则 ts 类型报错timer = window.setInterval(() => {const date = new Date()time.value = date.toLocaleTimeString()}, 1000)
})onBeforeUnmount(() => {timer && window.clearInterval(timer)
})

官方推荐

概述
Vue 在大多数常见场景下性能都是很优秀的,通常不需要手动优化。然而,总会有一些具有挑战性的场景需要进行针对性的微调。在本节中,我们将讨论用 Vue 开发的应用在性能方面该注意些什么。
首先,让我们区分一下 web 应用性能的两个主要方面:

  • 页面加载性能:首次访问时,应用展示出内容与达到可交互状态的速度。这通常会用 Google 所定义的一系列 Web 指标 (Web Vitals) 来进行衡量,如最大内容绘制 (Largest Contentful Paint,缩写为 LCP) 和首次输入延迟 (First Input Delay,缩写为 FID)。
  • 更新性能:应用响应用户输入更新的速度。比如当用户在搜索框中输入时结果列表的更新速度,或者用户在一个单页面应用 (SPA) 中点击链接跳转页面时的切换速度。
    虽然最理想的情况是将两者都最大化,但是不同的前端架构往往会影响到在这些方面是否能达到更理想的性能。此外,你所构建的应用的类型极大地影响了你在性能方面应该优先考虑的问题。因此,优化性能的第一步是为你的应用类型确定合适的架构:
  • 查看使用 Vue 的多种方式这一章看看如何用不同的方式围绕 Vue 组织架构。
  • Jason Miller 在 Application Holotypes 一文中讨论了 Web 应用的类型以及它们各自的理想实现/交付方式。

分析选项

为了提高性能,我们首先需要知道如何衡量它。在这方面,有一些很棒的工具可以提供帮助:
用于生产部署的负载性能分析:

  • PageSpeed Insights
  • WebPageTest
    用于本地开发期间的性能分析:
  • Chrome 开发者工具“性能”面板
    • app.config.performance 将会开启 Vue 特有的性能标记,标记在 Chrome 开发者工具的性能时间线上。
  • Vue 开发者扩展也提供了性能分析的功能。
    页面加载优化
    页面加载优化有许多跟框架无关的方面 - 这份 web.dev 指南提供了一个全面的总结。这里,我们将主要关注和 Vue 相关的技巧。

选用正确的架构

如果你的用例对页面加载性能很敏感,请避免将其部署为纯客户端的 SPA,而是让服务器直接发送包含用户想要查看的内容的 HTML 代码。纯客户端渲染存在首屏加载缓慢的问题,这可以通过服务器端渲染 (SSR) 或静态站点生成 (SSG) 来缓解。查看 SSR 指南以了解如何使用 Vue 实现 SSR。如果应用对交互性要求不高,你还可以使用传统的后端服务器来渲染 HTML,并在客户端使用 Vue 对其进行增强。
如果你的主应用必须是 SPA,但还有其他的营销相关页面 (落地页、关于页、博客等),请单独部署这些页面!理想情况下,营销页面应该是包含尽可能少 JS 的静态 HTML,并用 SSG 方式部署。

包体积与 Tree-shaking 优化

一个最有效的提升页面加载速度的方法就是压缩 JavaScript 打包产物的体积。当使用 Vue 时有下面一些办法来减小打包产物体积:

  • 尽可能地采用构建步骤
    • 如果使用的是相对现代的打包工具,许多 Vue 的 API 都是可以被 tree-shake 的。举例来说,如果你根本没有使用到内置的 Transition组件,它将不会被打包进入最终的产物里。Tree-shaking 也可以移除你源代码中其他未使用到的模块。
    • 当使用了构建步骤时,模板会被预编译,因此我们无须在浏览器中载入 Vue 编译器。这在同样最小化加上 gzip 优化下会相对缩小 14kb 并避免运行时的编译开销。
  • 在引入新的依赖项时要小心包体积膨胀!在现实的应用中,包体积膨胀通常因为无意识地引入了过重的依赖导致的。
    • 如果使用了构建步骤,应当尽量选择提供 ES 模块格式的依赖,它们对 tree-shaking 更友好。举例来说,选择 lodash-es 比 lodash 更好。
    • 查看依赖的体积,并评估与其所提供的功能之间的性价比。如果依赖对 tree-shaking 友好,实际增加的体积大小将取决于你从它之中导入的 API。像 bundlejs.com 这样的工具可以用来做快速的检查,但是根据实际的构建设置来评估总是最准确的。
  • 如果你只在渐进式增强的场景下使用 Vue,并想要避免使用构建步骤,请考虑使用 petite-vue (只有 6kb) 来代替。

代码分割

代码分割是指构建工具将构建后的 JavaScript 包拆分为多个较小的,可以按需或并行加载的文件。通过适当的代码分割,页面加载时需要的功能可以立即下载,而额外的块只在需要时才加载,从而提高性能。
像 Rollup (Vite 就是基于它之上开发的) 或者 webpack 这样的打包工具可以通过分析 ESM 动态导入的语法来自动进行代码分割:

// lazy.js 及其依赖会被拆分到一个单独的文件中
// 并只在 `loadLazy()` 调用时才加载
function loadLazy() {return import('./lazy.js')
}

懒加载对于页面初次加载时的优化帮助极大,它帮助应用暂时略过了那些不是立即需要的功能。在 Vue 应用中,这可以与 Vue 的异步组件搭配使用,为组件树创建分离的代码块:

import { defineAsyncComponent } from 'vue'// 会为 Foo.vue 及其依赖创建单独的一个块
// 它只会按需加载
//(即该异步组件在页面中被渲染时)
const Foo = defineAsyncComponent(() => import('./Foo.vue'))

懒加载对于页面初次加载时的优化帮助极大,它帮助应用暂时略过了那些不是立即需要的功能。在 Vue 应用中,这可以与 Vue 的异步组件搭配使用,为组件树创建分离的代码块:

import { defineAsyncComponent } from 'vue'// 会为 Foo.vue 及其依赖创建单独的一个块
// 它只会按需加载
//(即该异步组件在页面中被渲染时)
const Foo = defineAsyncComponent(() => import('./Foo.vue'))

对于使用了 Vue Router 的应用,强烈建议使用异步组件作为路由组件。Vue Router 已经显性地支持了独立于 defineAsyncComponent 的懒加载。查看懒加载路由了解更多细节。

更新优化

Props 稳定性
在 Vue 之中,一个子组件只会在其至少一个 props 改变时才会更新。思考以下示例:

<ListItem  v-for="item in list"  :id="item.id"  :active-id="activeId" />

在 ListItem 组件中,它使用了 id 和 activeId 两个 props 来确定它是否是当前活跃的那一项。虽然这是可行的,但问题是每当 activeId 更新时,列表中的每一个 ListIte 都会跟着更新!
理想情况下,只有活跃状态发生改变的项才应该更新。我们可以将活跃状态比对的逻辑移入父组件来实现这一点,然后让 ListItem 改为接收一个 active prop:

<ListItem  v-for="item in list"  :id="item.id"  :active="item.id === activeId" />

现在,对于大多数的组件来说,activeId 改变时,它们的 active prop 都会保持不变,因此它们无需再更新。总结一下,这个技巧的核心思想就是让传给子组件的 props 尽量保持稳定。

v-once

v-once 是一个内置的指令,可以用来渲染依赖运行时数据但无需再更新的内容。它的整个子树都会在未来的更新中被跳过。查看它的 API 参考手册可以了解更多细节。

v-memo

v-memo 是一个内置指令,可以用来有条件地跳过某些大型子树或者 v-for 列表的更新。查看它的 API 参考手册可以了解更多细节。

const seen = new WeakSet()export const transformMemo: NodeTransform = (node, context) => {if (node.type === NodeTypes.ELEMENT) {const dir = findDir(node, 'memo')if (!dir || seen.has(node)) {return}seen.add(node)return () => {const codegenNode =node.codegenNode ||(context.currentNode as PlainElementNode).codegenNodeif (codegenNode && codegenNode.type === NodeTypes.VNODE_CALL) {// non-component sub tree should be turned into a blockif (node.tagType !== ElementTypes.COMPONENT) {convertToBlock(codegenNode, context)}node.codegenNode = createCallExpression(context.helper(WITH_MEMO), [dir.exp!,createFunctionExpression(undefined, codegenNode),`_cache`,String(context.cached++)]) as MemoExpression}}}
}

WeakSet
WeakSet、WeakMap、Set、Map 他们有什么区别?
Weakxxx 都属于弱引用
https://zh.javascript.info/weakmap-weakset

通用优化

以下技巧能同时改善页面加载和更新性能。

大型虚拟列表
所有的前端应用中最常见的性能问题就是渲染大型列表。无论一个框架性能有多好,渲染成千上万个列表项都会变得很慢,因为浏览器需要处理大量的 DOM 节点。
但是,我们并不需要立刻渲染出全部的列表。在大多数场景中,用户的屏幕尺寸只会展示这个巨大列表中的一小部分。我们可以通过列表虚拟化来提升性能,这项技术使我们只需要渲染用户视口中能看到的部分。
要实现列表虚拟化并不简单,幸运的是,你可以直接使用现有的社区库:

  • vue-virtual-scroller
  • vue-virtual-scroll-grid
  • vueuc/VVirtualList

减少大型不可变数据的响应性开销
Vue 的响应性系统默认是深度的。虽然这让状态管理变得更直观,但在数据量巨大时,深度响应性也会导致不小的性能负担,因为每个属性访问都将触发代理的依赖追踪。好在这种性能负担通常只有在处理超大型数组或层级很深的对象时,例如一次渲染需要访问 100,000+ 个属性时,才会变得比较明显。因此,它只会影响少数特定的场景。
Vue 确实也为此提供了一种解决方案,通过使用 shallowRef() 和 shallowReactive() 来绕开深度响应。浅层式 API 创建的状态只在其顶层是响应式的,对所有深层的对象不会做任何处理。这使得对深层级属性的访问变得更快,但代价是,我们现在必须将所有深层级对象视为不可变的,并且只能通过替换整个根状态来触发更新:

const shallowArray = shallowRef([/* 巨大的列表,里面包含深层的对象 */
])// 这不会触发更新...
shallowArray.value.push(newObject)
// 这才会触发更新
shallowArray.value = [...shallowArray.value, newObject]// 这不会触发更新...
shallowArray.value[0].foo = 1
// 这才会触发更新
shallowArray.value = [{...shallowArray.value[0],foo: 1},...shallowArray.value.slice(1)
]

避免不必要的组件抽象

有些时候我们会去创建无渲染组件或高阶组件 (用来渲染具有额外 props 的其他组件) 来实现更好的抽象或代码组织。虽然这并没有什么问题,但请记住,组件实例比普通 DOM 节点要昂贵得多,而且为了逻辑抽象创建太多组件实例将会导致性能损失。
需要提醒的是,只减少几个组件实例对于性能不会有明显的改善,所以如果一个用于抽象的组件在应用中只会渲染几次,就不用操心去优化它了。考虑这种优化的最佳场景还是在大型列表中。想象一下一个有 100 项的列表,每项的组件都包含许多子组件。在这里去掉一个不必要的组件抽象,可能会减少数百个组件实例的无谓性能消耗。

相关文章:

Vue开发中常见优化手段总结

Tree Shaking or Trunk 动态引入&#xff08;Dynamic Imports&#xff09; 动态引入是指在代码执行过程中&#xff0c;根据需要动态加载模块&#xff0c;而不是在应用启动时一次性加载所有模块。这可以通过JavaScript的import()函数实现&#xff0c;它返回一个Promise对象&…...

IDEA无法创建java8、11项目创建出的pom.xml为空

主要是由于Spring3.X版本不支持JDK8&#xff0c;JDK11&#xff0c;最低支持JDK17 解决的话要不就换成JDK17以上的版本&#xff0c;但是不太现实 另外可以参考以下方式解决 修改spring初始化服务器地址为阿里云的 https://start.aliyun.com/...

TCP/IP网络编程-C++(上)

TCP/IP网络编程-C &#xff08;上&#xff09; 一、基于TCP的服务端/客户端1、server端代码2、client端代码3、socket() 函数3.1、函数原型3.2、参数解析3.2.1、协议族&#xff08;domain参数&#xff09;3.2.2、套接字类型&#xff08;type参数&#xff09;3.2.3、最终使用的协…...

在线绘制Nature Communication同款双色、四色火山图,突出感兴趣的基因

导读&#xff1a;火山图通常使用三种颜色分别表示显著上调&#xff0c;显著下调和不显著。通过为特定的数据点添加另一种颜色&#xff0c;可以创建双色或四色火山图&#xff0c;从而更直观地突出感兴趣的数据点。 《Nature Communication》文章“Molecular and functional land…...

ctfshow pwn wp

文章目录 Test_your_ncpwn-0pwn1pwn2pwn3pwn4 前置基础pwn5pwn6pwn7pwn8pwn9pwn10pwn11pwn12pwn13&#xff1a;gcc编译执行C语言代码pwn14&#xff1a;gcc编译执行C语言代码pwn15&#xff1a;nasm编译asm&#xff0c;ld链接为可执行文件pwn16&#xff1a;gcc编译汇编文件.s为可…...

【数据结构实战篇】用C语言实现你的私有队列

&#x1f3dd;️专栏&#xff1a;【数据结构实战篇】 &#x1f305;主页&#xff1a;f狐o狸x 在前面的文章中我们用C语言实现了栈的数据结构&#xff0c;本期内容我们将实现队列的数据结构 一、队列的概念 队列&#xff1a;只允许在一端进行插入数据操作&#xff0c;在另一端…...

数据结构 (11)串的基本概念

一、串的定义 1.串是由一个或者多个字符组成的有限序列&#xff0c;一般记为&#xff1a;sa1a2…an&#xff08;n≥0&#xff09;。其中&#xff0c;s是串的名称&#xff0c;用单括号括起来的字符序列是串的值&#xff1b;ai&#xff08;1≤i≤n&#xff09;可以是字母、数字或…...

快速高效求素数|质数的方法—Java(模板)

判断素数|质数方法时间效率:线性筛法>埃氏筛法>试除法 在写算法题的时候&#xff0c;各种各样跟素数有关的题目非常常见&#xff0c;本文列出了三种常见的判断素数的方法 三种求素数方法的优缺点 一、试除法 试除法的基本思想是&#xff1a;判断一个数 x 是否为素数&…...

探秘嵌入式位运算:基础与高级技巧

目录 一、位运算基础知识 1.1. 位运算符 1.1.1. 与运算&#xff08;&&#xff09; 1.1.2. 或运算&#xff08;|&#xff09; 1.1.3. 异或运算&#xff08;^&#xff09; 1.1.4. 取反运算&#xff08;~&#xff09; 1.1.5. 双重按位取反运算符&#xff08;~~&#xf…...

iOS 17.4 Not Installed

0x00 系统警告 没有安装 17.4 的模拟器&#xff0c;任何操作都无法进行&#xff01; 点击 OK 去下载&#xff0c;完成之后&#xff0c;依旧是原样&#xff01; 0x01 解决办法 1、先去官网下载对应的模拟器&#xff1a; https://developer.apple.com/download/all/?q17.4 …...

RestTemplate 使用教程

RestTemplate 是 Spring 框架提供的一种用于执行HTTP请求的同步客户端。它简化了与HTTP服务器的交互&#xff0c;并支持RESTful Web服务。 1. 添加依赖 首先&#xff0c;确保你的项目中包含了Spring Web的支持。如果你使用的是Maven&#xff0c;在pom.xml文件中添加如下依赖&…...

windows下安装wsl的ubuntu,同时配置深度学习环境

写在前面&#xff0c;本次文章只是个人学习记录&#xff0c;不具备教程的作用。个别信息是网上的&#xff0c;我会标注&#xff0c;个人是gpt生成的 安装wsl 直接看这个就行&#xff1b;可以不用备份软件源。 https://blog.csdn.net/weixin_44301630/article/details/1223900…...

【贪心算法第五弹——300.最长递增子序列】

目录 1.题目解析 题目来源 测试用例 2.算法原理 3.实战代码 代码解析 注意本题还有一种动态规划的解决方法&#xff0c;贪心的方法就是从动态规划的方法总结而来&#xff0c;各位可以移步博主的另一篇博客先了解一下&#xff1a;动态规划-子序列问题——300.长递增子序列…...

【数据分析】基于GEE解析2000-2020年武汉市FVC时空变化特征

武汉市FVC时空变化特征解析 1. 写在前面2. 2000~2020年武汉市FVC时空变化特征解析2.1. 数据获取与预处理2.2. 辐射定标和大气校正2.3. 云层和云影去除2.4. FVC计算2.5. 时空分析2.6. 代码1. 写在前面 🌍✨在应对全球气候变化和环境监测的挑战中,植被盖度(Fraction Vegetati…...

springboot实战(19)(条件分页查询、PageHelper、MYBATIS动态SQL、mapper映射配置文件、自定义类封装分页查询数据集)

引言&#xff1a; 该类博客的学习是基于b站黑马视频springbootvue视频学习&#xff01;具体围绕项目——"大事件"进行实战学习。 目录 一、功能介绍&#xff08;需求&#xff09;。 1、文章列表功能基本介绍。 2、条件分页查询功能与注意。 3、前端页面效果。&#x…...

Mongo数据库 --- Mongo Pipeline

Mongo数据库 --- Mongo Pipeline 什么是Mongo PipelineMongo Pipeline常用的几个StageExplanation with example:MongoDB $matchMongoDB $projectMongoDB $groupMongoDB $unwindMongoDB $countMongoDB $addFields Some Query Examples在C#中使用Aggreagtion Pipeline**方法一: …...

Docker部署mysql:8.0.31+dbsyncer

Docker部署mysql8.0.31 创建本地mysql配置文件 mkdir -p /opt/mysql/log mkdir -p /opt/mysql/data mkdir -p /opt/mysql/conf cd /opt/mysql/conf touch my.config [mysql] #设置mysql客户端默认字符集 default-character-setUTF8MB4 [mysqld] #设置3306端口 port33…...

银河麒麟桌面系统——桌面鼠标变成x,窗口无关闭按钮的解决办法

银河麒麟桌面系统——桌面鼠标变成x&#xff0c;窗口无关闭按钮的解决办法 1、支持环境2、详细操作说明步骤1&#xff1a;用root账户登录电脑步骤2&#xff1a;导航到kylin-wm-chooser目录步骤3&#xff1a;编辑default.conf文件步骤4&#xff1a;重启电脑 3、结语 &#x1f49…...

【微服务】 Eureka和Ribbon

一、Eureka 服务调用出现的问题&#xff1a;在远程调用另一个服务时&#xff0c;我们采用的解决办法是发送一次http请求&#xff0c;每次环境的变更会产生新的地址&#xff0c;所以采用硬编码会出现很多麻烦&#xff0c;并且为了应对并发问题&#xff0c;采用分布式部署&#…...

C++设计模式(工厂模式)

一、介绍 1.动机 在软件系统中&#xff0c;经常面临着创建对象的工作&#xff0c;这些对象有可能是一系列相互依赖的对象&#xff1b;由于需求的变化&#xff0c;需要创建的对象的具体类型经常变化&#xff0c;同时也可能会有更多系列的对象需要被创建。 如何应对这种变化&a…...

nodejs第三方库sharp对图片的操作生成新图片、压缩、添加文字水印及图片水印等

Sharp是一个基于libvips的高性能Node.js图像处理库&#xff0c;它提供了广泛的功能&#xff0c;包括调整大小、裁剪、旋转、格式转换等。Sharp可以处理多种图像格式&#xff0c;并且能够高效地转换图像格式。 相关说明及用法看&#xff1a;https://sharp.nodejs.cn/ 安装&#…...

uniapp-vue2引用了vue-inset-loader插件编译小程序报错

报错信息 Error: Vue packages version mismatch: - vue3.2.45 (D:\qjy-myApp\admin-app\node_modules\vue\index.js) - vue-template-compiler2.7.16 (D:\qjy-myApp\admin-app\node_modules\vue-template-compiler\package.json) This may cause things to work incorrectly.…...

计算机的错误计算(一百六十七)

摘要 将计算机的错误计算&#xff08;一百六十六&#xff09;中算式的分母有理化&#xff0c;然后再在 MATLAB 讨论其计算精度。本节说明&#xff0c;MATLAB 的输出与&#xff08;一百六十六&#xff09;的输出几乎一致&#xff0c;有效数字的错误率也相同。 例1. 探讨 …...

交叉编译openSSH

升级原系统中的SSHd服务 由于原系统自带的SSH版本过低存在漏洞风险&#xff0c;所以需要升级新版本的SSH 交叉编译前准备 需要下面三个库&#xff0c;都是开源的&#xff0c;去对应的网站下载即可 openssh-9.6p1.tar.gz openssl-1.1.1w.tar.gz zlib-1.3.1.tar.gz 这里没有…...

从零开始学GeoServer源码(二)添加支持arcgis切片功能

文章目录 参考文章环境背景1、配置打包好的程序1.1、下载GeoServer的war包1.2、下载GeoWebCache1.3、拷贝jar包1.4、修改配置文件1.4.1、拷贝geowebcache-arcgiscache-context.xml1.4.2、修改geowebcache-core-context.xml1.4.3、修改geowebcache-servlet.xml 1.5、配置切片信息…...

Android OTA 更新面试题及参考答案

什么是 OTA 更新&#xff1f; OTA 更新即空中下载技术&#xff08;Over-the-Air Technology&#xff09;更新&#xff0c;是一种通过无线网络对移动设备的系统软件或应用程序进行远程更新的技术手段 。 其原理是设备通过移动网络或 Wi-Fi 连接到服务器&#xff0c;服务器检测设…...

搜维尔科技:通过Touch力反馈主手实时通讯机械臂,进行远程操作

通过Touch力反馈主手实时通讯机械臂&#xff0c;进行远程操作 搜维尔科技&#xff1a;通过Touch力反馈主手实时通讯机械臂&#xff0c;进行远程操作...

Java ArrayList 与顺序表:在编程海洋中把握数据结构的关键之锚

我的个人主页 我的专栏&#xff1a;Java-数据结构&#xff0c;希望能帮助到大家&#xff01;&#xff01;&#xff01;点赞❤ 收藏❤ 前言&#xff1a;在 Java编程的广袤世界里&#xff0c;数据结构犹如精巧的建筑蓝图&#xff0c;决定着程序在数据处理与存储时的效率、灵活性以…...

React中事件处理和合成事件:理解与使用

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…...

在Vue3项目中引入省市区联动插件

1. 打开HBuilder X 图1 2. 新建一个空项目 文件->新建->项目->uni-app 填写项目名称&#xff1a;vue3demo 选择项目存放目录&#xff1a;D:/HBuilderProjects 一定要注意vue的版本&#xff0c;当前选择的版本为vue3 图2 点击“创建”之后进入项目界面 图3 其中各文件…...

动态内存管理(c语言)

我们通常开辟空间的方式 int val 20; //大小为4个字节 char arr[10] {0} //开辟出一块连续的空间且大小为10 但是上面开辟空间方式的特点 1.空间开辟大小是固定的 2.数组在声明得时候&#xff0c;必须指定数组得长度&#xff0c;它所需要得内存在编译时分配 但是以上的方式不能…...

SLF4J日志快速上手

tags: SpringBoot 日志 快速上手 SLF4J日志快速上手 第一步&#xff1a;添加日志相关配置 logging:level:root: INFO # 设置全局日志级别为 INFO&#xff0c;只显示重要的日志信息&#xff08;略过 DEBUG 和 TRACE 级别&#xff09;# org.hibernate.SQL: DEBUG # 对于 Hiber…...

【PyTorch】(基础三)---- 图像读取和展示

图像读取和展示 pytorch本身并不提供图像的读取和展示功能&#xff0c;利用pytorch执行计算机视觉任务的时候&#xff0c;通常是利用opencv等工具先进行图像处理&#xff0c;然后将结果转化成tensor类型传递给pytorch&#xff0c;在pytorch执行之后&#xff0c;也可以将tensor…...

【纪念365天】我的创作纪念日

过去的一年 没有注意加入csdn已经有一年了。 这几天翻看小猴儿的通知才发现时间来到了一年的纪念日。稍稍思索想要将这一段时间的学习到的知识以及偶然遇到的机遇做一下总结。 上一次写纪念日是来到csdn128天的时候&#xff0c; 200天前我的学习状态是非常疯狂的。 只记得我当时…...

flink学习(7)——window

概述 窗口的长度(大小): 决定了要计算最近多长时间的数据 窗口的间隔: 决定了每隔多久计算一次 举例&#xff1a;每隔10min,计算最近24h的热搜词&#xff0c;24小时是长度&#xff0c;每隔10分钟是间隔。 窗口的分类 1、根据window前是否调用keyBy分为键控窗口和非键控窗口…...

第十六届蓝桥杯模拟赛第二期题解—Java

第十六届蓝桥杯模拟赛/校赛第二期个人题解&#xff0c;有错误的地方欢迎各位大佬指正 问题一(填空题) 【问题描述】 如果一个数 p 是个质数&#xff0c;同时又是整数 a 的约数&#xff0c;则 p 称为 a 的一个质因数。 请问&#xff0c; 2024 的最大的质因数是多少&#xff1f; …...

数据库-MySQL-Dynamic-Datasource源码解析

文章目录 前言一、简介二、整体流程三、核心解析四、总结 前言 多数据源的应用在日常项目中也是很常见的场景。 dynamic-datasource的功能&#xff0c;用起来的确很方便&#xff0c;只需要一个DS注解&#xff0c;加上一些简单的配置即可完成多数据源的切换。究竟是怎么做到的…...

uniapp+vue2+uview2.0导航栏组件二次封装

样式 代码 <template><view class"navBar"><u-navbar :title"title" :titleColor"titleColor" :bgColor"bgColor" :safeAreaInsetTop"safeAreaInsetTop":autoBack"true" leftClick"leftClic…...

【Git 工具】用 IntelliJ IDEA 玩转 Git 分支与版本管理

文章目录 一、使用 IDEA 配置和操作 Git1.1 查看 Idea 中的 Git 配置1.2 克隆 Github 项目到本地 二、版本管理2.1 提交并推送修改2.2 拉取远程仓库2.3 查看历史2.4 版本回退 三、分支管理3.1 新建分支3.2 切换分支3.2 合并分支3.4 Cherry-Pick 参考资料 一、使用 IDEA 配置和操…...

异或-java-leetcode

1486.数组异或操作 给你两个整数&#xff0c;n 和 start 。 数组 nums 定义为&#xff1a;nums[i] start 2*i&#xff08;下标从 0 开始&#xff09;且 n nums.length 。 请返回 nums 中所有元素按位异或&#xff08;XOR&#xff09;后得到的结果。 示例 1&#xff1a; 输入…...

Jmeter中的测试片段和非测试原件

1&#xff09;测试片段 1--测试片段 功能特点 重用性&#xff1a;将常用的测试元素组合成一个测试片段&#xff0c;便于在多个线程组中重用。模块化&#xff1a;提高测试计划的模块化程度&#xff0c;使测试计划更易于管理和维护。灵活性&#xff1a;可以通过模块控制器灵活地…...

NeurIPS 2024 有效投稿达 15,671 篇,数据集版块内容丰富

NeurIPS&#xff0c;全称 Neural Information Processing Systems Conference&#xff0c;是神经信息处理系统的年度学术会议。该会议始于 1987 年&#xff0c;当时名为 NIPS。随着人工智能领域的快速发展&#xff0c;其影响力逐渐扩大&#xff0c;被越来越多的研究者和企业关注…...

力扣101. 对称二叉树

给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 提示&#xff1a; 树中节点数目在范围 [1, 1000] 内-100 < Node.val < 100 进阶&#xff1a;你可以运用递归和迭代两种方法解决这个问题吗&#xff1f; 代码&#xff1a; /*** Definition for a binary …...

Ubuntu 环境下的 C/C++ 编译与调试配置

详细教学文档&#xff1a;Ubuntu 环境下的 C/C 编译与调试配置 本文档将手把手引导你完成在 Ubuntu 环境中设置 VS Code 的 tasks.json 和 launch.json&#xff0c;实现以下目标&#xff1a; 统一管理输出文件&#xff1a;将所有编译生成的可执行文件统一存放到项目的 build …...

『VUE』36. Vue的应用概念(分析流程)

目录 创建应用挂载应用可执行文件公共资源总结 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 创建应用 首先引入createApp ,然后借助createApp 创造一个app对象 main.js import { createApp } from "vue"; import A…...

《基于FPGA的便携式PWM方波信号发生器》论文分析(三)——数码管稳定显示与系统调试

一、论文概述 基于FPGA的便携式PWM方波信号发生器是一篇由任青颖、庹忠曜、黄洵桢、李智禺和张贤宇 等人发表的一篇期刊论文。该论文主要研究了一种新型的信号发生器&#xff0c;旨在解决传统PWM信号发生器在移动设备信号调控中存在的精准度低和便携性差的问题 。其基于现场可编…...

mac上的建议xftp 工具

mac上的建议xftp 工具 最近使用mac比较频繁了&#xff0c;但是第一次重度使用mac里面有很多的工具都是新的&#xff0c;有的window版本的工具无法使用。 xftp 的平替 Cyberduck 从它的官网上下载是免费的&#xff0c;但是如果使用 Apple store 要花费198呢。这不就剩下一大笔…...

Hive | Hive 表如何查看所有分区

文章目录 概述使用 SHOW PARTITIONS 命令查看特定分区的信息获取详细的分区信息总结 概述 Apache Hive 是一个构建在 Hadoop 之上的数据仓库工具&#xff0c;它提供了 SQL 类似的查询语言&#xff08;称为 HiveQL&#xff09;&#xff0c;使得用户能够更容易地进行大数据处理和…...

MySQL系列之数据类型(Numeric)

导览 前言一、数值类型综述二、数值类型详解1. NUMERIC1.1 UNSIGNED或SIGNED1.2 数据类型划分 2. Integer类型取值和存储要求3. Fixed-Point类型取值和存储要求4. Floating-Point类型取值和存储要求 结语精彩回放 前言 MySQL系列最近三篇均关注了和我们日常工作或学习密切相关…...

4.6 JMeter HTTP信息头管理器

欢迎大家订阅【软件测试】 专栏&#xff0c;开启你的软件测试学习之旅&#xff01; 文章目录 前言1 HTTP信息头管理器的位置2 常见的HTTP请求头3 添加 HTTP 信息头管理器4 应用场景 前言 在 JMeter 中&#xff0c;HTTP信息头管理器&#xff08;HTTP Header Manager&#xff09…...