2025年01月02日浙江鼎永前端面试
目录
- webpack 和 vite 区别
- react fiber 架构
- vue diff 算法
- react diff 算法
- hooks 源码
- 垂直水平布局
- 项目介绍
- 单点登录
- 大文件上传
- 微前端
1. webpack 和 vite 区别
Webpack 和 Vite 是两种不同的前端构建工具,它们在设计理念、性能表现和使用场景上存在显著差异。以下是它们的详细对比:
1. Webpack
1.1 基本概念
Webpack 是一个模块打包工具,主要用于将各种资源(如 JavaScript、CSS、图片等)作为模块处理,并生成优化后的静态资源文件。它通过配置文件来定义如何处理这些模块和资源。
1.2 工作原理
- 打包过程:Webpack 在开发和生产环境中都会进行完整的打包过程,包括解析依赖关系、编译代码、优化资源等。
- 热更新:Webpack 提供了热模块替换(HMR),可以在开发过程中实现局部更新,但仍然需要重新打包整个应用。
- 配置复杂:Webpack 配置较为复杂,需要手动配置各种加载器(loaders)和插件(plugins)来处理不同类型的资源。
1.3 优点
- 成熟稳定:Webpack 是目前最流行的构建工具之一,社区活跃,插件丰富,适用于各种复杂的项目需求。
- 功能强大:支持多种资源类型和复杂的构建流程,可以灵活配置以满足不同项目的需求。
- 广泛支持:有大量的第三方插件和工具链支持,能够处理几乎所有类型的前端资源。
1.4 缺点
- 启动时间长:由于需要解析和打包所有依赖,Webpack 的启动时间相对较长,尤其是在大型项目中。
- 配置复杂:需要编写详细的配置文件,对于初学者来说有一定的学习曲线。
2. Vite
2.1 基本概念
Vite 是一个由 Vue.js 核心团队开发的新一代前端构建工具,旨在提供更快的开发体验。它基于 ES 模块(ESM)原生支持,利用浏览器的原生模块解析能力,实现了按需加载和即时编译。
2.2 工作原理
- 开发服务器:Vite 在开发模式下不会进行打包,而是启动一个轻量级的开发服务器,直接从磁盘读取源文件并进行即时编译。
- 按需编译:只有当模块被请求时才会进行编译,因此启动速度非常快,通常只需几百毫秒。
- 原生 ESM 支持:Vite 利用浏览器对 ESM 的原生支持,减少了构建工具的负担,提升了开发效率。
- 热更新:Vite 提供了更高效的 HMR 实现,能够在不刷新页面的情况下快速更新模块,极大提高了开发体验。
2.3 优点
- 启动速度快:由于不需要预先打包所有资源,Vite 的启动时间非常短,尤其适合大型项目。
- 开发体验好:即时编译和高效 HMR 提供了流畅的开发体验,减少了等待时间。
- 配置简单:默认配置已经足够应对大多数场景,用户无需过多配置即可开始开发。
- 现代特性支持:内置对 TypeScript、JSX 等现代特性的支持,减少了额外配置的工作量。
2.4 缺点
- 生产环境依赖:虽然 Vite 在开发环境中表现出色,但在生产环境中仍然需要借助 Rollup 或其他工具进行打包,增加了构建链的复杂性。
- 生态系统相对较小:相比 Webpack,Vite 的插件和工具链生态还不够完善,某些高级功能可能需要自行实现或寻找替代方案。
3. 总结
特性 | Webpack | Vite |
---|---|---|
工作原理 | 完整打包,解析依赖,编译代码 | 按需编译,即时加载,利用浏览器原生 ESM |
启动时间 | 较长,尤其是大型项目 | 非常快,通常只需几百毫秒 |
热更新 (HMR) | 局部更新,但需要重新打包 | 更高效,不刷新页面,快速更新模块 |
配置复杂度 | 复杂,需要详细配置 | 简单,默认配置已足够 |
适用场景 | 复杂项目,需要高度定制化 | 快速开发,中小型项目,追求极致开发体验 |
生态系统 | 成熟,插件丰富 | 相对较小,但发展迅速 |
示例回答
**面试官**:请谈谈 Webpack 和 Vite 的区别。**我**:Webpack 和 Vite 是两种不同的前端构建工具,它们在设计理念、性能表现和使用场景上存在显著差异。以下是它们的主要区别:**Webpack**:
- **工作原理**:Webpack 在开发和生产环境中都会进行完整的打包过程,包括解析依赖关系、编译代码、优化资源等。
- **启动时间**:由于需要解析和打包所有依赖,Webpack 的启动时间相对较长,尤其是在大型项目中。
- **热更新 (HMR)**:Webpack 提供了热模块替换(HMR),可以在开发过程中实现局部更新,但仍然需要重新打包整个应用。
- **配置复杂度**:Webpack 配置较为复杂,需要手动配置各种加载器(loaders)和插件(plugins)来处理不同类型的资源。
- **适用场景**:Webpack 适用于复杂项目,特别是需要高度定制化的场景。**Vite**:
- **工作原理**:Vite 在开发模式下不会进行打包,而是启动一个轻量级的开发服务器,直接从磁盘读取源文件并进行即时编译。
- **启动时间**:由于不需要预先打包所有资源,Vite 的启动时间非常短,通常只需几百毫秒。
- **热更新 (HMR)**:Vite 提供了更高效的 HMR 实现,能够在不刷新页面的情况下快速更新模块,极大提高了开发体验。
- **配置复杂度**:Vite 默认配置已经足够应对大多数场景,用户无需过多配置即可开始开发。
- **适用场景**:Vite 适合快速开发,特别是在中小型项目中,追求极致的开发体验。**总结**:
- **Webpack** 更适合复杂项目,提供了强大的功能和丰富的插件生态。
- **Vite** 则以其快速的启动时间和高效的开发体验著称,特别适合中小型项目和快速迭代的开发场景。通过理解 Webpack 和 Vite 的区别,可以根据项目的具体需求选择合适的构建工具,从而更好地提升开发效率和用户体验。
综上所述,Vite 在开发时的启动速度、HMR 性能、配置的简洁性、对现代前端框架的支持、插件生态的易用性以及对 TypeScript 的支持等方面都有一定的优势,尤其是对于开发体验和开发效率有更高要求的项目,Vite 是一个很好的选择。然而,Webpack 仍然是一个强大的工具,对于一些复杂的、需要高度定制化的项目,Webpack 的丰富插件和强大的配置能力可以更好地满足需求。在选择时,可以根据项目的具体情况和团队的经验来决定使用哪种工具。
在面试中回答这个问题时,可以结合实际的项目经验,例如:“在我之前的项目中,使用 Vite 开发一个 Vue 3 项目,开发服务器的启动速度非常快,几乎是瞬间完成,而之前使用 Webpack 时,启动时间会随着项目规模的增加而显著增加。而且 Vite 的 HMR 性能很好,修改代码后可以立即看到效果,无需长时间等待,相比之下,Webpack 的 HMR 有时会出现整个页面刷新的情况,影响开发体验。Vite 的配置也更加简洁,对于 TypeScript 的处理也很方便,而在使用 Webpack 时,需要更多的配置来处理 TypeScript 模块和实现类似的开发体验。不过,如果是一个需要高度定制化的大型项目,Webpack 可以通过其丰富的插件和复杂的配置来满足需求,但这也需要更多的时间和精力去配置和维护。”
通过这样的回答,可以向面试官展示你对两种打包工具的深入了解和在实际项目中的应用经验。
2. react fiber 架构
React Fiber 是 React 16.x 版本及以后采用的协调算法架构,它旨在解决旧协调器在大型应用中性能瓶颈问题,下面从设计动机、核心概念、工作原理和优势方面详细介绍。
设计动机
在旧的协调器中,采用的是递归的方式进行虚拟 DOM 的比较和更新,这种方式一旦开始就无法暂停。如果应用规模大,虚拟 DOM 树层级深,递归调用栈会很长,执行时间就会比较久。在执行期间,浏览器无法处理其他任务,比如用户的交互、动画渲染等,会造成页面卡顿,用户体验不佳。React Fiber 架构就是为了解决这一问题而设计的,它让协调过程可以被中断、恢复,将工作拆分成多个小任务,在浏览器空闲时执行。
核心概念
- Fiber节点:Fiber 是一个 JavaScript 对象,它代表了虚拟 DOM 树中的一个节点。每个 Fiber 节点包含了该节点的状态、属性、类型等信息,同时还包含了与其他 Fiber 节点的连接关系,如父节点、子节点、兄弟节点等。通过这些连接关系,Fiber 节点构成了一个链表结构的 Fiber 树。
- 渲染阶段:此阶段会遍历 Fiber 树,根据节点的变化生成副作用列表(记录需要执行的 DOM 更新操作)。这个阶段是可以中断和恢复的。
- 提交阶段:将渲染阶段生成的副作用列表应用到真实 DOM 上。这个阶段是不可中断的,必须一次性完成,以保证用户不会看到不完整的 UI 更新。
工作原理
- 任务拆分:将协调过程拆分成多个小的工作单元,每个工作单元就是一个 Fiber 节点的处理。
- 调度执行:借助
requestIdleCallback
或requestAnimationFrame
这样的 API,React 能够在浏览器的空闲时段执行工作单元。在每个工作单元完成后,检查是否还有剩余时间,如果有则继续执行下一个工作单元;如果时间不够,则暂停当前工作,保存现场,等浏览器有空闲时间时再恢复执行。 - 链表遍历:Fiber 节点通过链表结构相连,React 采用深度优先遍历的方式遍历 Fiber 树,处理每个 Fiber 节点。遍历过程中,会根据节点的变化生成副作用列表。
- 副作用执行:渲染阶段结束后,进入提交阶段,React 会遍历副作用列表,将所有的 DOM 更新操作一次性应用到真实 DOM 上。
代码示例及解释
import React, { useState } from 'react';function App() {const [count, setCount] = useState(0);return (<div><p>You clicked {count} times</p><button onClick={() => setCount(count + 1)}>Click me</button></div>);
}export default App;
在这个简单的 React 应用中,每次点击按钮时,count
状态会更新。React Fiber 架构会对这次更新进行处理:
- 当
setCount
被调用,React 会创建一个新的 Fiber 节点来表示更新后的状态。 - React 调度器会在浏览器空闲时开始处理这个新的 Fiber 节点,将其与旧的 Fiber 节点进行比较,生成副作用列表。
- 最后在提交阶段,将副作用列表中的 DOM 更新操作应用到真实 DOM 上,页面上的计数器会更新显示新的计数。
优势
- 流畅的用户体验:通过将协调过程拆分成小任务,并在浏览器空闲时执行,避免了长时间阻塞浏览器主线程,使得页面在更新过程中仍然可以响应用户的交互和动画渲染,提升了用户体验。
- 优先级调度:React Fiber 可以为不同的更新任务分配不同的优先级,优先处理高优先级的任务,比如用户的输入事件,确保关键更新能够及时得到处理。
3. vue diff 算法
核心区别
Vue2 和 Vue3 的 diff 算法主要有三个区别:
- 算法实现:
- Vue2 使用双端比较算法
- Vue3 使用快速 diff 算法
- 性能优化:
- Vue3 增加了静态标记(PatchFlag)
- Vue3 增加了静态提升(hoistStatic)
- Vue3 使用最长递增子序列优化了对比流程
- 时间复杂度:
- Vue2 的时间复杂度是 O(n^2)
- Vue3 在理想情况下可以达到 O(n)
双端比较(Vue2)
Vue2 的双端比较会同时从新旧子节点的两端开始比较,会进行以下四种比较:
- 新前与旧前
- 新后与旧后
- 新后与旧前
- 新前与旧后
如果四种都未命中,才会进行遍历查找。
快速diff(Vue3)
Vue3 的 diff 算法步骤:
- 先从头部开始比对
- 再从尾部开始比对
- 如果还有剩余节点:
- 新增:处理新增的节点
- 删除:处理需要删除的节点
- 移动:使用最长递增子序列来优化节点移动
如果面试官继续追问
Vue3 为什么更快?
- 编译优化:
- 静态标记:标记动态内容,只对动态内容进行 diff
- 静态提升:静态节点只会被创建一次
- Block Tree:将动态节点收集到一个数组中
- 算法优化:
- 最长递增子序列算法减少了节点移动次数
- 使用 Map 数据结构优化了节点查找
2. PatchFlag 是什么?
PatchFlag 是 Vue3 新增的一个标记,用于标识节点的动态内容类型:
- 1: 动态文本节点
- 2: 动态 class
- 4: 动态 style
- 8: 动态属性
- 16: 动态事件
等等…这样在 diff 的时候可以只关注动态内容,提高性能。
3. 实际应用影响
这些优化在实际应用中的效果:
- 大型列表渲染更快
- 组件更新性能更好
- 内存占用更少
加分回答
如果想要在面试中脱颖而出,可以补充:
-
Vue3 diff 算法借鉴了 inferno 的算法实现
-
Vue3 还有其他性能优化:
- 事件缓存
- 基于 Proxy 的响应式系统
- 更好的 TypeScript 支持
- 在实践中,我们可以:
- 使用 key 来帮助 diff 算法识别节点
- 避免不必要的节点嵌套
- 合理使用 v-show 和 v-if
记住:
- 回答要由浅入深
- 先说核心区别
- 再解释具体实现
- 最后谈优化和实践
- 如果面试官继续追问,再展开细节
4. react diff 算法
React Diff 算法是 React 用于对比虚拟 DOM 树差异的核心算法,它能够高效地找出新旧虚拟 DOM 树之间的差异,从而最小化对真实 DOM 的操作,提高渲染性能。下面为你详细介绍:
设计理念
由于完整比较两棵树的时间复杂度为 O ( n 3 ) O(n^3) O(n3),这样的复杂度在大型应用中会导致性能问题。React 基于两个假设对算法进行了优化,将时间复杂度降低到 O ( n ) O(n) O(n),这两个假设为:
- 不同类型的元素会产生不同的树:如果两个元素类型不同,React 会直接销毁旧元素对应的树,创建新元素对应的树。
- 开发者可以通过
key
来暗示哪些子元素在不同渲染中可能保持不变:通过为列表项提供唯一的key
,React 可以识别出哪些元素在更新前后是同一个元素,从而提高比较效率。
比较策略
元素类型比较
- 类型相同:如果两个元素类型相同,React 会保留 DOM 节点,仅更新其属性。例如,对于两个
<div>
元素,只会更新它们的属性,而不会重新创建整个<div>
节点。 - 类型不同:当元素类型不同时,React 会直接销毁旧元素及其所有子元素,然后创建新元素及其子元素。比如从
<div>
变为<span>
,就会销毁原<div>
节点及其子节点,再创建<span>
节点。
组件比较
- 组件类型相同:React 会保持组件实例不变,仅更新其 props,并调用组件的
render
方法获取新的虚拟 DOM 进行比较。 - 组件类型不同:如同元素类型不同的情况,会卸载旧组件,创建新组件。
列表比较
当处理列表时,为了识别哪些元素被添加、删除或移动,React 引入了 key
的概念。如果没有 key
,React 会默认按照顺序比较元素,这样在插入或删除元素时会导致效率低下。而使用唯一的 key
,React 可以准确地识别每个元素,从而高效地进行更新。
代码示例及解释
import React, { useState } from 'react';function App() {const [items, setItems] = useState([{ id: 1, name: 'Item 1' }, { id: 2, name: 'Item 2' }]);const addItem = () => {const newItem = { id: Date.now(), name: `Item ${items.length + 1}` };setItems([...items, newItem]);};return (<div><button onClick={addItem}>Add Item</button><ul>{items.map(item => (<li key={item.id}>{item.name}</li>))}</ul></div>);
}export default App;
在这个例子中:
items
数组存储了列表项的数据。- 点击
Add Item
按钮时,会生成一个新的列表项并添加到items
数组中。 map
方法遍历items
数组,为每个列表项生成一个<li>
元素,并通过key
属性指定了唯一标识。这样 React 在更新列表时,就能利用key
高效地识别哪些元素是新增的,哪些是已有的,从而只对必要的 DOM 进行更新。
总结
React Diff 算法通过上述的优化策略,在保持高效性能的同时,让开发者可以像操作真实 DOM 一样方便地操作虚拟 DOM。但在使用时,开发者需要注意合理使用 key
,避免使用数组索引作为 key
,以充分发挥 Diff 算法的优势。
5. hooks 源码
要理解 React Hooks 的源码实现,我们先从整体思路入手,再结合部分简化代码来辅助理解。
整体思路
- 状态管理:使用链表来存储每个组件的 Hooks 状态。每个 Hook 对应链表中的一个节点,节点包含了 Hook 的状态、更新函数等信息。
- 渲染协调:在组件渲染时,按顺序依次调用 Hooks,根据链表中存储的状态进行计算和更新。
- 更新机制:当调用 Hook 的更新函数(如
setState
)时,会触发组件的重新渲染,同时更新链表中对应 Hook 的状态。
简化源码示例及解释
以下是一个简化版的 React Hooks 实现,帮助你理解其核心原理:
// 全局变量,用于存储当前正在渲染的组件的 Hooks 链表
let currentlyRenderingFiber = null;
// 当前处理的 Hook 在链表中的索引
let workInProgressHook = null;// 模拟 Fiber 节点,代表一个组件实例
function FiberNode() {this.memoizedState = null; // 存储该组件的 Hooks 链表
}// useState Hook 的简化实现
function useState(initialState) {let hook;if (currentlyRenderingFiber) {// 如果是首次渲染if (!workInProgressHook) {hook = {memoizedState: initialState, // 存储当前状态queue: [], // 存储状态更新队列next: null // 指向下一个 Hook 节点};if (!currentlyRenderingFiber.memoizedState) {currentlyRenderingFiber.memoizedState = hook;} else {let lastHook = currentlyRenderingFiber.memoizedState;while (lastHook.next) {lastHook = lastHook.next;}lastHook.next = hook;}workInProgressHook = hook;} else {// 如果是后续渲染hook = workInProgressHook;workInProgressHook = workInProgressHook.next;}}// 状态更新函数const dispatch = (action) => {// 简单处理,将更新动作添加到队列hook.queue.push(action);// 模拟组件重新渲染currentlyRenderingFiber = { memoizedState: null };workInProgressHook = null;// 重新计算状态let newState = hook.memoizedState;hook.queue.forEach((action) => {if (typeof action === 'function') {newState = action(newState);} else {newState = action;}});hook.memoizedState = newState;hook.queue = [];
};return [hook.memoizedState, dispatch];
}// 模拟组件渲染函数
function Component() {currentlyRenderingFiber = new FiberNode();workInProgressHook = null;const [count, setCount] = useState(0);console.log('Count:', count);setCount(count + 1);return null;
}// 调用组件渲染
Component();
代码解释
- 全局变量:
currentlyRenderingFiber
:代表当前正在渲染的组件的 Fiber 节点,存储该组件的 Hooks 链表。workInProgressHook
:用于在渲染过程中记录当前处理的 Hook 节点。
- FiberNode 类:模拟 Fiber 节点,其中
memoizedState
存储该组件的 Hooks 链表。 - useState 函数:
- 首次渲染时,创建一个新的 Hook 节点,并将其添加到 Hooks 链表中。
- 后续渲染时,从链表中获取对应的 Hook 节点。
dispatch
函数用于更新状态,将更新动作添加到队列中,重新计算状态并更新 Hook 节点的memoizedState
。
- Component 函数:模拟组件渲染,调用
useState
Hook 获取状态和更新函数,然后更新状态。
注意事项
- 这只是一个简化版的实现,实际的 React 源码要复杂得多,包含了更多的错误处理、优化和边界情况处理。
- React Hooks 的调用顺序非常重要,因为它们是按顺序存储在链表中的,调用顺序的改变会导致状态混乱。
6. 垂直水平布局
在网页开发中,实现元素的垂直水平布局是常见需求,下面从不同的技术方案为你详细介绍实现方法。
1. 使用 Flexbox 布局
Flexbox 是一种一维布局模型,它为盒状模型提供了强大的对齐和分布能力,能方便地实现元素的垂直水平居中。
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><style>/* 父元素设置为 Flex 容器 */.parent {display: flex;justify-content: center; /* 水平居中 */align-items: center; /* 垂直居中 */width: 300px;height: 300px;background-color: lightblue;}/* 子元素 */.child {width: 50px;height: 50px;background-color: lightcoral;}</style>
</head><body><div class="parent"><div class="child"></div></div>
</body></html>
解释:
display: flex
将父元素设置为 Flex 容器。justify-content: center
让子元素在水平方向上居中。align-items: center
让子元素在垂直方向上居中。
2. 使用 Grid 布局
Grid 是二维布局模型,提供了强大的网格布局能力,也能轻松实现元素的垂直水平居中。
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><style>/* 父元素设置为 Grid 容器 */.parent {display: grid;place-items: center; /* 同时实现垂直和水平居中 */width: 300px;height: 300px;background-color: lightblue;}/* 子元素 */.child {width: 50px;height: 50px;background-color: lightcoral;}</style>
</head><body><div class="parent"><div class="child"></div></div>
</body></html>
解释:
display: grid
将父元素设置为 Grid 容器。place-items: center
是align-items: center
和justify-items: center
的缩写,能同时实现子元素在垂直和水平方向上的居中。
3. 使用绝对定位和负边距(适用于已知宽高的元素)
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><style>/* 父元素设置为相对定位 */.parent {position: relative;width: 300px;height: 300px;background-color: lightblue;}/* 子元素设置为绝对定位 */.child {position: absolute;top: 50%;left: 50%;width: 50px;height: 50px;margin-top: -25px; /* 负边距为元素高度的一半 */margin-left: -25px; /* 负边距为元素宽度的一半 */background-color: lightcoral;}</style>
</head><body><div class="parent"><div class="child"></div></div>
</body></html>
解释:
position: relative
将父元素设置为相对定位,作为子元素绝对定位的参考。position: absolute
、top: 50%
和left: 50%
将子元素的左上角定位到父元素的中心。- 通过负边距将子元素向上和向左移动自身宽高的一半,实现垂直水平居中。
4. 使用绝对定位和 transform
(适用于未知宽高的元素)
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><style>/* 父元素设置为相对定位 */.parent {position: relative;width: 300px;height: 300px;background-color: lightblue;}/* 子元素设置为绝对定位 */.child {position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%); /* 向上和向左移动自身宽高的 50% */background-color: lightcoral;}</style>
</head><body><div class="parent"><div class="child"></div></div>
</body></html>
解释:
- 同样先将父元素设置为相对定位,子元素设置为绝对定位并定位到父元素中心。
transform: translate(-50%, -50%)
能将子元素向上和向左移动自身宽高的 50%,实现垂直水平居中,且无需知道子元素的具体宽高。
7. 项目介绍
在面试中介绍低代码前端平台项目,可按以下结构清晰、全面且突出重点地展示你的项目:
项目概述
- 项目背景与目标:阐述搭建低代码平台的缘由,比如企业内部业务需求频繁变更,传统开发模式效率低、成本高,因此开发低代码平台以提升开发效率、降低技术门槛,使非专业开发者也能快速搭建业务应用。
- 项目规模与周期:说明项目的规模,如参与人数、涉及的业务模块数量等,以及从开始到上线所经历的时间。例如,项目历时6个月,由5名前端开发人员、3名后端开发人员和2名测试人员共同完成,涵盖了表单设计、页面布局、数据展示等多个业务模块。
功能特性
- 核心功能:详细介绍平台的主要功能,如可视化组件拖拽、配置式开发、数据绑定等。举例说明,用户可在可视化界面通过拖拽文本框、按钮等组件到指定位置,快速完成页面布局;通过简单配置即可实现组件与数据源的绑定,实时展示数据。
- 特色功能:突出平台的独特之处,如支持自定义组件、多语言切换、与第三方系统集成等。以自定义组件为例,用户可根据业务需求创建个性化组件,并在平台中重复使用,大大提高了开发的灵活性和复用性。
技术实现
- 前端技术栈:提及使用的前端框架(如Vue、React)、构建工具(如Webpack、Vite)、状态管理库(如Vuex、Redux)等。解释选择这些技术的原因,例如使用Vue框架是因为其简单易用、响应式设计和丰富的生态系统,能够快速实现组件化开发。
- 低代码实现原理:介绍平台实现低代码开发的关键技术,如元数据驱动、模板引擎、代码生成等。说明如何通过元数据描述业务逻辑和页面结构,利用模板引擎生成代码框架,最后根据用户配置动态生成可运行的代码。
项目挑战与解决方案
- 遇到的问题:分享在项目开发过程中遇到的难题,如组件兼容性问题、性能优化问题、数据安全问题等。
- 解决方法:阐述针对这些问题采取的解决方案。以组件兼容性问题为例,通过对不同浏览器和设备进行测试,使用浏览器前缀和Polyfill技术来确保组件在各种环境下都能正常显示和使用。
项目成果
- 业务指标提升:展示平台上线后带来的业务效益,如开发效率提升了多少百分比、开发成本降低了多少、应用上线周期缩短了多少等。
- 用户反馈:分享用户对平台的评价和反馈,如操作简单方便、功能满足需求、提高了工作效率等,以证明平台的实用性和价值。
未来规划
- 功能扩展:说明对平台未来功能的规划,如增加新的组件类型、支持更多的数据交互方式、优化用户界面等。
- 技术升级:提及计划采用的新技术和优化方案,如引入微前端架构、使用更高效的算法提升性能等。
示例话术
您好,我参与开发的这个低代码前端平台,主要是为了解决公司内部业务系统开发效率低、成本高的问题。项目历时6个月,由一个10人的团队共同完成。
平台的核心功能包括可视化组件拖拽和配置式开发。用户可以在可视化界面上像搭积木一样,通过拖拽各种组件来快速完成页面布局,然后通过简单的配置实现组件与数据源的绑定。我们平台的特色功能是支持自定义组件,用户可以根据自己的业务需求创建个性化组件,并且可以在不同的项目中重复使用。
在技术实现上,我们使用了Vue框架和Vite构建工具。Vue的组件化开发和响应式设计让我们能够快速实现各种功能,而Vite的快速构建和热更新功能提高了我们的开发效率。平台采用元数据驱动的方式,通过定义元数据来描述业务逻辑和页面结构,然后利用模板引擎生成代码框架,最后根据用户的配置动态生成可运行的代码。
在项目开发过程中,我们遇到了组件兼容性的问题,不同的浏览器和设备对组件的显示效果有差异。我们通过对各种浏览器和设备进行测试,使用浏览器前缀和Polyfill技术来解决这个问题。
平台上线后,开发效率提升了50%,开发成本降低了30%,应用上线周期从原来的几周缩短到了几天。用户反馈平台操作简单方便,大大提高了他们的工作效率。
未来,我们计划增加更多的组件类型,支持更复杂的数据交互方式,并且引入微前端架构来提升平台的可维护性和扩展性。
以上就是我对这个低代码前端平台项目的介绍,您有什么问题可以随时问我。
8. 单点登录
单点登录(Single Sign-On,简称 SSO)是一种身份验证机制,允许用户使用一组凭证(如用户名和密码)访问多个相互关联但独立的应用系统,避免了用户在不同系统中重复登录的繁琐过程。下面将从原理、实现方式、优缺点和应用场景几个方面为你详细介绍:
原理
单点登录的核心原理是通过一个统一的身份验证中心(Identity Provider,简称 IdP)来管理用户的身份信息和登录状态。当用户首次访问某个应用系统时,若未登录,系统会将用户重定向到身份验证中心进行登录。登录成功后,身份验证中心会生成一个令牌(Token),并将其返回给用户浏览器。用户再次访问其他关联应用系统时,浏览器会携带该令牌,应用系统会将令牌发送给身份验证中心进行验证,验证通过后,用户即可直接访问该应用系统,无需再次登录。
实现方式
基于Cookie的单点登录
这是一种较为简单的实现方式,身份验证中心在用户登录成功后,会在用户浏览器中设置一个共享的Cookie。其他关联应用系统在用户访问时,会检查该Cookie是否存在且有效。如果有效,则认为用户已经登录,允许其访问系统。
<!-- 身份验证中心登录成功后设置Cookie -->
<script>document.cookie = "sso_token=xxxxxx; domain=.example.com; path=/";// 重定向到目标应用系统window.location.href = "https://app1.example.com";
</script>
基于令牌(Token)的单点登录
身份验证中心在用户登录成功后,会生成一个包含用户身份信息的令牌(如JWT),并将其返回给用户浏览器。用户在访问其他应用系统时,浏览器会将令牌发送给应用系统,应用系统再将令牌发送给身份验证中心进行验证。
// 身份验证中心生成JWT令牌
const jwt = require('jsonwebtoken');
const secretKey = 'your_secret_key';
const payload = { username: 'user1' };
const token = jwt.sign(payload, secretKey, { expiresIn: '1h' });
// 返回令牌给用户浏览器
res.json({ token: token });// 应用系统验证令牌
const token = req.headers['authorization'].split(' ')[1];
jwt.verify(token, secretKey, (err, decoded) => {if (err) {res.status(401).json({ message: 'Invalid token' });} else {// 验证通过,允许用户访问res.json({ message: 'Access granted' });}
});
基于OAuth 2.0和OpenID Connect的单点登录
OAuth 2.0是一种授权框架,用于在不同系统之间安全地共享用户资源。OpenID Connect是在OAuth 2.0基础上构建的身份验证协议,提供了用户身份信息的标准化格式。通过OAuth 2.0和OpenID Connect,用户可以使用第三方身份验证服务(如Google、Facebook)进行单点登录。
优缺点
优点
- 提高用户体验:用户只需登录一次,即可访问多个应用系统,大大减少了登录的繁琐过程,提高了使用效率。
- 降低管理成本:企业只需维护一个统一的身份验证中心,减少了用户账号管理的工作量和成本。
- 增强安全性:集中的身份验证和管理可以更好地控制用户的访问权限,提高系统的安全性。
缺点
- 单点故障风险:如果身份验证中心出现故障,用户将无法登录任何关联的应用系统,影响业务的正常运行。
- 安全风险:由于所有应用系统都依赖于身份验证中心的令牌验证,一旦令牌泄露或被篡改,可能会导致用户信息泄露和系统安全问题。
- 集成复杂度高:将多个不同的应用系统集成到单点登录系统中,需要进行大量的开发和配置工作,增加了项目的复杂度和成本。
应用场景
- 企业内部系统:企业内部通常有多个业务系统,如ERP、CRM、OA等,通过单点登录可以让员工使用一组凭证访问所有系统,提高工作效率。
- 互联网平台:一些大型互联网平台,如阿里巴巴、腾讯等,旗下有多个子应用,通过单点登录可以让用户在不同应用之间无缝切换,提升用户体验。
- 教育领域:学校或教育机构的在线学习平台、教务管理系统等,通过单点登录可以方便学生和教师使用。
示例回答话术
面试官您好,单点登录是一种让用户使用一组凭证就能访问多个关联应用系统的身份验证机制。它能极大提升用户体验,降低企业管理成本,同时增强系统安全性。
单点登录的核心原理是通过一个统一的身份验证中心来管理用户的登录状态。用户首次登录时,身份验证中心验证用户凭证,验证通过后生成一个令牌。后续用户访问其他关联系统时,系统会将令牌发送给身份验证中心进行验证,验证通过即可直接访问。
实现单点登录有几种常见方式。基于 Cookie 的方式比较简单,身份验证中心登录成功后设置共享 Cookie,应用系统检查该 Cookie 判断用户登录状态,但受同源策略限制。基于令牌的方式安全性更高,使用如 JWT 这样的令牌在客户端和服务器间传递用户信息,可跨域使用。基于 OAuth 2.0 和 OpenID Connect 的方式则借助第三方身份验证服务,方便用户使用已有账号登录。
我之前参与过一个企业内部系统的单点登录项目,项目目标是整合多个业务系统,实现统一登录。我们选用了 JWT 作为令牌,前端使用 Vue 框架处理登录跳转和令牌传递,后端用 Node.js 验证令牌和管理用户会话。项目中遇到了令牌过期和跨域问题,我们通过设置合理的令牌有效期和配置 CORS 解决了这些问题。
在安全方面,我们采用 HTTPS 协议保证数据传输安全,对令牌进行签名和验证防止盗用。性能上,通过缓存用户登录状态和优化令牌验证流程,减少了身份验证中心的响应时间。
以上就是我对单点登录的理解和实践经验,您有什么问题可以随时问我。
9. 大文件上传
在Web开发里,上传大文件会碰到超时、内存占用大等难题。下面从不同角度介绍大文件上传的解决方案。
常见思路
- 切片上传:把大文件分割成多个小文件,再依次上传这些小文件,最后在服务端将小文件合并成原始大文件。此方法能避免单个大文件上传超时的问题,还能实现断点续传。
- 断点续传:上传中断时,记录已上传的部分,下次上传时从断点处继续,无需重新上传整个文件。
- 并发上传:同时上传多个文件切片,以此加快上传速度。
前端实现(以切片上传为例)
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>大文件上传</title>
</head><body><input type="file" id="fileInput"><button id="uploadButton">上传</button><script>const fileInput = document.getElementById('fileInput');const uploadButton = document.getElementById('uploadButton');uploadButton.addEventListener('click', async () => {const file = fileInput.files[0];if (!file) return;const chunkSize = 1024 * 1024; // 每个切片大小为 1MBconst totalChunks = Math.ceil(file.size / chunkSize);for (let i = 0; i < totalChunks; i++) {const start = i * chunkSize;const end = Math.min(start + chunkSize, file.size);const chunk = file.slice(start, end);const formData = new FormData();formData.append('chunk', chunk);formData.append('filename', file.name);formData.append('chunkIndex', i);formData.append('totalChunks', totalChunks);try {await fetch('/upload', {method: 'POST',body: formData});} catch (error) {console.error('上传切片失败:', error);}}// 通知服务器合并切片await fetch('/merge', {method: 'POST',headers: {'Content-Type': 'application/json'},body: JSON.stringify({ filename: file.name, totalChunks })});});</script>
</body></html>
代码解释:
- 文件切片:借助
file.slice
方法把文件分割成多个大小为 1MB 的切片。 - 切片上传:利用
FormData
封装每个切片的数据,通过fetch
方法把切片上传到服务器。 - 合并切片:所有切片上传完成后,发送请求通知服务器合并切片。
后端实现(以 Node.js 为例)
const express = require('express');
const fs = require('fs');
const path = require('path');
const multer = require('multer');const app = express();
const upload = multer({ dest: 'uploads/temp/' });// 处理切片上传
app.post('/upload', upload.single('chunk'), (req, res) => {const { filename, chunkIndex, totalChunks } = req.body;const chunkPath = req.file.path;const tempDir = path.join(__dirname, 'uploads/temp', filename);if (!fs.existsSync(tempDir)) {fs.mkdirSync(tempDir, { recursive: true });}const newPath = path.join(tempDir, `${chunkIndex}`);fs.renameSync(chunkPath, newPath);res.status(200).send('切片上传成功');
});// 处理切片合并
app.post('/merge', express.json(), async (req, res) => {const { filename, totalChunks } = req.body;const tempDir = path.join(__dirname, 'uploads/temp', filename);const finalPath = path.join(__dirname, 'uploads', filename);const writeStream = fs.createWriteStream(finalPath);for (let i = 0; i < totalChunks; i++) {const chunkPath = path.join(tempDir, `${i}`);const readStream = fs.createReadStream(chunkPath);await new Promise((resolve) => {readStream.pipe(writeStream, { end: false });readStream.on('end', resolve);});fs.unlinkSync(chunkPath);}fs.rmdirSync(tempDir);res.status(200).send('文件合并成功');
});const port = 3000;
app.listen(port, () => {console.log(`服务器运行在端口 ${port}`);
});
代码解释:
- 切片接收:运用
multer
中间件接收前端上传的切片,将其保存到临时目录。 - 切片合并:收到合并请求后,按顺序读取临时目录中的切片文件,写入最终文件,合并完成后删除临时文件和目录。
补充说明
- 断点续传:前端可在本地记录已上传的切片索引,上传前先向服务器查询哪些切片已上传,只上传未上传的切片。
- 并发上传:前端可使用
Promise.all
或其他并发控制方法同时上传多个切片,提高上传效率。
示例回答话术
面试官您好,大文件上传在实际开发中确实存在一些挑战,比如超时问题、内存占用过高以及网络波动导致的上传中断等。
针对这些问题,常见的解决方案是切片上传、断点续传和并发上传。切片上传是把大文件分割成小的切片,分别上传后在服务端合并,这样能避免单个大文件上传超时,还支持断点续传和并发上传。断点续传则是记录已上传的切片信息,上传中断后可从断点处继续。并发上传可以同时上传多个切片,加快上传速度。
前端实现时,首先使用 File.slice 方法对文件进行切片,再用 FormData 封装切片数据,通过 fetch 或 XMLHttpRequest 发送请求。为实现断点续传,可在本地存储已上传切片的索引,上传前与服务器核对。
后端使用中间件(如 multer)接收切片,保存到临时目录。收到合并请求后,按顺序读取临时切片,写入最终文件,合并完成后删除临时文件。
为了优化用户体验,还可以添加进度条展示上传进度,对上传失败的情况给出明确提示并提供重试机制。同时,要注意上传文件的安全性,对文件类型和大小进行限制,确保数据传输安全。
10. 微前端
在面试中回答微前端相关问题,可以按照以下思路清晰、全面地进行阐述:
基础概念与优势
- 概念阐述:先简洁解释微前端的定义,即它是一种借鉴微服务理念的前端架构风格,把前端应用拆分成多个小型、自治的应用,这些小应用能独立开发、部署,最后集成成一个完整的大型前端应用。
- 优势列举:着重强调微前端带来的好处。比如技术栈无关性,不同团队可依据自身情况和项目需求选用合适的技术栈,像团队A用Vue开发用户界面,团队B用React实现业务逻辑;高可维护性,每个微前端应用相对独立,代码结构清晰,便于后续维护和功能扩展;独立部署特性,各个微前端应用能独立进行部署,无需等待其他部分,提升了开发和部署效率;团队自治方面,不同团队负责不同的微前端应用,提高了团队自主性和工作效率。
实现方式及适用场景
- 详细介绍实现方式:
- 路由分发式:说明其原理是主应用通过路由系统,根据不同的URL路径将请求导向不同的微前端应用。例如,主应用监听路由变化,当用户访问
/product
路径时,加载商品管理微前端应用。适用场景为应用功能模块划分清晰,可按路由区分不同业务模块的情况。 - 微内核式:解释主应用作为微内核,负责加载和管理各个以插件形式集成的微前端应用。就像主应用提供插件加载机制,微前端应用按特定规范开发成插件,主应用启动时动态加载。适用于需要灵活扩展功能,以插件形式添加新业务模块的场景。
- 构建时集成:指出在构建阶段使用Webpack等工具将多个微前端应用的代码合并打包成一个整体应用。适用于对应用性能要求较高,希望在构建阶段就完成代码整合的场景。
- 运行时集成:强调在运行时主应用根据需要动态加载微前端应用的代码,如通过
script
标签加载JavaScript文件。适用于需要根据用户操作或业务需求动态展示不同功能模块的场景。
- 路由分发式:说明其原理是主应用通过路由系统,根据不同的URL路径将请求导向不同的微前端应用。例如,主应用监听路由变化,当用户访问
- 对比不同方式的优缺点:分析每种实现方式的优缺点,比如路由分发式实现简单,但可能存在路由配置复杂的问题;微内核式灵活性高,但集成难度较大;构建时集成性能较好,但不够灵活;运行时集成灵活度高,但有性能开销。
通信机制讲解
介绍微前端应用之间常见的通信机制,如:
- 事件总线:主应用提供全局事件总线,微前端应用通过发布和订阅事件来交换信息。例如,一个微前端应用发布“数据更新”事件,另一个应用订阅该事件并做出相应处理。
- URL参数:通过URL传递简单数据,实现微前端应用间的数据交互。如在URL中携带商品ID,让另一个微前端应用根据ID展示商品详情。
- Web Storage:利用
localStorage
或sessionStorage
存储数据,供不同微前端应用访问。但要注意数据的有效期和安全性。 - postMessage:用于不同窗口或iframe之间的跨域通信,确保在不同源的微前端应用间能安全地传递消息。
实践经验分享(若有)
- 项目背景与目标:描述参与的微前端项目背景,如企业业务扩展需要整合多个系统,目标是提高开发效率和用户体验。
- 技术选型与实现:说明项目中选用的实现方式和通信机制,以及具体的技术栈。例如采用路由分发式,使用Vue和React作为技术栈,通过事件总线进行通信。讲述项目中的关键实现步骤,如如何划分微前端应用、如何进行路由配置、如何处理应用间的通信等。
- 遇到的问题与解决方案:分享项目中遇到的挑战,如样式冲突、通信故障、性能问题等,并阐述采取的解决办法。比如通过CSS模块化解决样式冲突,使用消息队列优化通信机制,采用代码分割和懒加载提升性能。
未来趋势与看法
提及对微前端未来发展趋势的理解,如与微服务架构的深度融合、在低代码/无代码开发中的应用等。表达自己对微前端的看法,强调其在现代前端开发中的重要性和发展潜力,同时也指出需要关注的问题,如安全性、标准化等。
示例回答话术
面试官您好,微前端是一种创新的前端架构风格,它把前端应用拆分成多个小型、自治的应用,能独立开发、部署,最后集成成完整的大型应用。这种架构有很多优势,技术栈无关让不同团队能根据需求选择合适技术,可维护性高使代码结构清晰,独立部署提升了开发和部署效率,团队自治也提高了团队的自主性。
实现微前端有几种常见方式。路由分发式通过主应用的路由系统,根据URL路径分发请求,适用于功能模块划分清晰的应用;微内核式以主应用为核心加载和管理插件式的微前端应用,适合灵活扩展功能的场景;构建时集成在构建阶段用工具合并代码,性能较好但灵活性稍差;运行时集成在运行时动态加载代码,灵活度高但有性能开销。
微前端应用间的通信机制也有多种。事件总线是全局的消息传递方式,URL参数可传递简单数据,Web Storage能存储数据供不同应用访问,postMessage用于跨域通信。
我之前参与过一个企业级微前端项目,项目目标是整合多个业务系统。我们采用路由分发式,用Vue和React开发不同模块,通过事件总线通信。项目中遇到了样式冲突和性能问题,我们通过CSS模块化解决样式问题,用代码分割和懒加载提升性能。
我认为微前端未来会和微服务架构深度融合,在低代码/无代码开发中也会有更多应用。它在现代前端开发中非常重要,但也需要关注安全性和标准化等问题。
以上就是我对微前端的理解和相关经验,您有任何问题都可以问我。
相关文章:
2025年01月02日浙江鼎永前端面试
目录 webpack 和 vite 区别react fiber 架构vue diff 算法react diff 算法hooks 源码垂直水平布局项目介绍单点登录大文件上传微前端 1. webpack 和 vite 区别 Webpack 和 Vite 是两种不同的前端构建工具,它们在设计理念、性能表现和使用场景上存在显著差异。以下…...
Redis全面学习指南
要全面掌握 Redis,需要系统化学习以下核心知识体系,涵盖基础到高级的各个方面,并理解其内部原理和实际应用场景: 一、Redis 核心特性与基础 基本概念与架构 定义:内存数据库,支持键值存储、缓存、消息队列等…...
python3最新版下载及python 3.13.1安装教程(附安装包)
文章目录 前言一、python 3.13.1下载二、python 3.13.1安装步骤1.准备安装文件2.启动安装程序3.选择安装方式4.等待安装完成5.完成安装 前言 在当今数字化时代,Python 以其简洁易读的语法和丰富的库资源,成为众多开发者喜爱的编程语言。Python 3.13.1 的…...
基于WebRtc,GB28181,Rtsp/Rtmp,SIP,JT1078,H265/WEB融合视频会议接入方案
智能融合视频会议系统方案—多协议、多场景、全兼容的一站式视频协作平台 OvMeet,LiveMeet针对用户核心痛点实现功能与用户价值 ,Web平台实现MCU多协议,H265/H264等不同编码监控,直播,会议,调度资源统一融合在一套界…...
css基础-display 常用布局
CSS display 属性详解 属性设置元素是否被视为块级或行级盒子以及用于子元素的布局,例如流式布局、网格布局或弹性布局。 一、基础显示模式 1. block 作用: 元素独占一行可设置宽高和内外边距默认宽度撑满父容器 应用场景: 布局容器&a…...
基于linux平台的C语言入门教程(7)类型转换
文章目录 1. 什么是类型转换?2. 隐式类型转换隐式类型转换的规则: 3. 显式类型转换显式类型转换的语法: 4. 示例代码代码解析:输出结果: 5. 常见问题问题 1:隐式类型转换会导致数据丢失吗?问题 …...
前端Wind CSS面试题及参考答案
目录 标准盒模型与 IE 盒模型的区别是什么?如何通过 box-sizing 属性切换这两种盒模型? 如何计算一个元素在标准盒模型下的总宽度(包含 margin、padding、border)? 父元素高度塌陷的原因是什么?请列举至少 3 种清除浮动的方法。 方法一:使用 clear 属性 方法二:使用…...
ROS melodic 安装 python3 cv_bridge
有时候,我们需要处理这些兼容性问题。此处列举我的过程,以供参考 mkdir -p my_ws_py39/src cd my_ws_py39 catkin_make_isolated-DPYTHON_EXECUTABLE/usr/bin/python3 \-DPYTHON_INCLUDE_DIR/usr/include/python3.8 \-DPYTHON_LIBRARY/usr/lib/x86_64-l…...
农用车一键启动工作原理
移动管家农用车一键启动的工作原理与普通汽车类似,主要依赖于无线射频识别技术(RFID)。以下是具体的工作步骤和原理: 智能钥匙识别: 车主携带智能钥匙靠近车辆时,钥匙通过发射射频信号与车辆进行交互。车辆…...
Swift 并发任务的协作式取消
在 Swift 并发(Swift Concurrency)中,任务(Task)不会被强行终止,而是采用**协作式取消(cooperative cancellation)**机制。这意味着任务会被标记为“已取消”,但是否真正…...
设计和布局硬件电路是嵌入式系统开发的重要环节
设计和布局硬件电路是嵌入式系统开发的重要环节,涉及从需求分析到原理图设计、PCB(印刷电路板)布局以及最终的硬件调试。以下是完整的流程和技术要点: 1. 硬件电路设计的基本流程 1.1 需求分析 明确功能需求:确定系统…...
防火墙虚拟系统实验
配置 [r1]interface GigabitEthernet 0/0/0 [r1-GigabitEthernet0/0/0]ip address 12.0.0.2 24 [r1]interface LoopBack 0 [r1-LoopBack0]ip address 100.1.1.1 24[fw]interface GigabitEthernet 0/0/0 [fw-GigabitEthernet0/0/0]service-manage all permit [fw]interfac…...
机器学习——KNN数据集划分
一、主要函数 sklearn.datasets.my_train_test_split() 该函数为Scikit-learn 中用于将数据集划分为训练集和测试集的函数,适用于机器学习模型的训练和验证。以下是详细解释: 1、函数签名 train_test_split(*arrays, # 输入的数据…...
C++基础系列【27】Raw String Literal
博主介绍:程序喵大人 35- 资深C/C/Rust/Android/iOS客户端开发10年大厂工作经验嵌入式/人工智能/自动驾驶/音视频/游戏开发入门级选手《C20高级编程》《C23高级编程》等多本书籍著译者更多原创精品文章,首发gzh,见文末👇…...
PyTorch核心基础知识点
PyTorch核心基础知识点,结合最新特性与工业级实践,按优先级和逻辑关系分层解析: ▍ 核心基石:张量编程(Tensor Programming) 1. 张量创建(8种生产级初始化) # 设备自动选择&#x…...
Springboot实现使用断点续传优化同步导入Excel
springboot实现使用断点续传优化同步导入Excel 需求前言断点续传前端实现后端实现完结撒花,如有需要收藏的看官,顺便也用发财的小手点点赞哈,如有错漏,也欢迎各位在评论区评论! 需求前言 在跨境电商系统中,…...
1、正点原子ZYNQ最小系统--GPIO之MIO控制LED笔记
1、ZYNQ PS中的外设通过MIO连接到PS端引脚;通过EMIO连接到PL端引脚。 2、Zynq-7000有54个MIO,有64个EMIO。 3、GPIO分为4个Bank,其中Bank0和Bank1连接到MIO;Bank2和Bank3连接到EMIO。 4、Bank1--22bit;Bank0--32bit;…...
基于STM32进行FFT滤波
文章目录 一、前言背景二、项目构思1. 确定FFT点数、采样率、采样点数2. 双缓存设计 三、代码实现1. STM32CubeMX配置和HAL库初始化2. 核心代码 四、效果展示和后话 一、前言背景 STM32 对 AD 采样信号进行快速傅里叶变换(FFT),以获取其频谱…...
ISCA Archive 的 关于 dysarthria 的所有文章摘要(1996~2024)
ISCA Archive 的 关于 dysarthria 的所有文章摘要(1996~2024) 构音障碍(Dysarthria)研究全景总结(1996–2024) 所有文章摘要(1996~2024) ISCA Archive 的 关于 dysarthria 的所有文…...
MySQL拒绝访问
1. 问题 使用图形界面工具连接MySQL数据库,拒绝访问! 2. 解决方法 以管理员的身份打开cmd,输入命令,启动MySQL net start mysql版本号 3. 参考 暂无...
ROM(只读存储器) 、SRAM(静态随机存储器) 和 Flash(闪存) 的详细解析
在嵌入式系统和其他计算机系统中,存储器是不可或缺的组成部分。不同类型的存储器各有其特点和应用场景。以下是 ROM(只读存储器)、SRAM(静态随机存储器) 和 Flash(闪存) 的详细解析。 1. ROM&am…...
Transformers x SwanLab:可视化NLP模型训练(2025最新版)
HuggingFace 的 Transformers 是目前最流行的深度学习训框架之一(100k Star),现在主流的大语言模型(LLaMa系列、Qwen系列、ChatGLM系列等)、自然语言处理模型(Bert系列)等,都在使用T…...
stm32-ADC
1.ADC:模拟到数字的转换器 1.1模拟 模拟信号:物理当中一切可感受到的都是模拟信号(连续的) 1.2数字: 数字信号:二进制数(离散的) 1.3a->c的过程 采样、量化 1.3.1量化的原理 方法&am…...
【1】Java 零基础入门学习(小白专用)
【1】Java 零基础入门学习 📚博客主页:代码探秘者 ✨专栏:《JavaSe从入门到精通》 其他更新ing… ❤️感谢大家点赞👍🏻收藏⭐评论✍🏻,您的三连就是我持续更新的动力❤️ 🙏作者水…...
《Python实战进阶》No26: CI/CD 流水线:GitHub Actions 与 Jenkins 集成
No26: CI/CD 流水线:GitHub Actions 与 Jenkins 集成 摘要 持续集成(CI)和持续部署(CD)是现代软件开发中不可或缺的实践,能够显著提升开发效率、减少错误并加速交付流程。本文将探讨如何利用 GitHub Actio…...
算力100问☞第92问:为什么各地热衷建设算力中心?
目录 1、宏观分析 2、政府角度分析 3、投资者角度分析 在数字化浪潮中,各地对算力中心建设的热情高涨,这一现象背后潜藏着诸多深层次的原因,涵盖了经济、科技、社会等多个维度,且彼此交织,共同驱动着这一发展趋势。 1、宏观分析 从经济结构转型的底层逻辑来看,全球经…...
w266农产品直卖平台的设计与实现
🙊作者简介:多年一线开发工作经验,原创团队,分享技术代码帮助学生学习,独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取,记得注明来意哦~🌹赠送计算机毕业设计600个选题excel文…...
OpenLayers集成天地图服务开发指南
以下是一份面向GIS初学者的OpenLayers开发详细教程,深度解析代码: 一、开发环境搭建 1.1 OpenLayers库引入 <!-- 使用CDN引入最新版OpenLayers --> <link rel"stylesheet" href"https://cdn.jsdelivr.net/npm/ollatest/ol.c…...
1、双指针法
关于每个知识点的例题 可以自己看力扣标准题解。也可以在哔哩哔哩上看。想看我的,就到github 看 - 库 ,介绍里写的算法讲解那些,里面有知识点,有题库。题库,每天都发题,可能跟博客的进度不一样。因为我上传…...
程序算法基础
程序设计基本概念 程序和算法 人们做任何事情都有一定的方法和程序,如:春节联欢晚会的节目单、开会的议程等,都是程序。在程序的指导下,可以有秩序地、有效的完成每一项工作。随着计算机的问世和普及,“程序”逐渐专…...
JavaScript基础-删除事件(解绑事件)
在现代Web开发中,动态地添加和移除事件处理器是构建交互式网页的关键技能之一。虽然添加事件处理器相对直观,但了解如何有效地移除或“解绑”这些处理器同样重要。这不仅有助于优化性能,还能防止潜在的内存泄漏问题。本文将介绍几种方法来删除…...
Selenium Web UI自动化测试:从入门到实战
引言 在当今快速迭代的软件开发周期中,自动化测试已成为保障产品质量、提升测试效率的核心手段之一。而针对Web应用的UI自动化测试,Selenium作为最流行的开源工具之一,凭借其跨浏览器、多语言支持(Python、Java、C#等)…...
AT_abc398_f [ABC398F] ABCBA
题目大意 请点击这里查看原题面。给定一个字符串 S S S,找出以 S S S 为前缀的最短回文字符串。 思路 观察样例三,容易发现只要寻找到一个合适的“对称轴”即可。可以考虑枚举对称轴位置,判断然后得到长度并计算答案串。但是这样显然会超…...
RK3568开发笔记-egtouch触摸屏ubuntu系统屏幕校准
目录 前言 一、官方egtouch触摸屏驱动校准 二、ubuntu系统xinput_calibrator工具校准 2.1. 工具安装 2.2. xinput_calibrator命令校准 总结 前言 在基于 RK3568 平台进行开发,并使用 egtouch 触摸屏搭配 ubuntu20.04 系统时,准确的屏幕校准对于良好的用户交互体验至关重要…...
使用uniapp的vite版本进行微信小程序开发,在项目中使用mqtt连接、订阅、发布信息
1、保证在微信公众平台配置socket合法域名 2、项目中使用mqtt 建议在package.json中配置"mqtt": “4.1.0”,使用这个版本的依赖 页面中引入mqtt并配置连接 // ts-ignoreimport * as mqtt from mqtt/dist/mqtt.js; //要使用这里面的const state reacti…...
【软件系统架构】单体架构
一、引言 在软件开发的漫长历程中,架构的选择一直是至关重要的决策。单体架构作为一种经典的架构模式,曾经在许多项目中发挥着不可替代的作用。虽然如今微服务等架构逐渐流行,但理解单体架构对于深入掌握软件架构体系仍然有着重要意义。 二、…...
强大的AI网站推荐(第三集)—— AskO3
网站:AskO3 号称:由华为全球技术服务部(GTS)基于盘古大模型构建的领域知识大模型 博主评价:学习网络安全必备的网站,ICT服务领域顶级AI网站,如果学习HCIA,园区配置等,也可…...
高速网络包处理,基础网络协议上内核态直接处理数据包,XDP技术的原理
文章目录 预备知识TCP/IP 网络模型(4层、7层)iptables/netfilterlinux网络为什么慢 DPDKXDPBFPeBPFXDPXDP 程序典型执行流通过网络协议栈的入包XDP 组成 使用 GO 编写 XDP 程序明确流程选择eBPF库编写eBPF代码编写Go代码动态更新黑名单 预备知识 TCP/IP…...
C++智能指针详解
C智能指针详解 目录 智能指针概述为什么需要智能指针C标准库中的智能指针 std::unique_ptrstd::shared_ptrstd::weak_ptr 智能指针的实际应用智能指针的最佳实践总结 智能指针概述 智能指针是C中用于自动管理动态分配内存的对象,它们遵循RAII(资源获…...
git 设置保存密码 git保存密码
目录 长久保存密码 长久保存密码 git push和git pull都能使用。 git config --global credential.helper store 然后执行一次 git pull,Git 会提示输入用户名和密码, 输入后保存路径: ~/.git-credentials , Windows系统&…...
clamav服务器杀毒(Linux服务器断网状态下如何进行clamav安装、查杀)
ClamAV服务器杀毒(服务器断网状态也可以使用该方法) 服务器因为挖矿病毒入侵导致断网,进行离线的clamav安装并查杀 安装包下载网址:https://www.clamav.net/downloads 安装.deb,如果服务器处于断网状态,可以…...
深入剖析 RocketMQ 的 ConsumerOffsetManager
在消息队列系统中,准确记录和管理消息的消费进度是保障系统可靠性和数据一致性的关键。RocketMQ 作为一款高性能、高可用的分布式消息队列,其 ConsumerOffsetManager 组件在消费进度管理方面发挥着至关重要的作用。本文将详细介绍 ConsumerOffsetManager…...
一文了解 threejs 中.bin 文件与 .gltf 文件 和 .glb 文件三者之间的关系
文章目录 前言一、.bin 文件的作用二、.gltf 文件的作用三、.gltf 和 .bin 的关系四、.glb 文件的作用五、如何查看或编辑 .bin 文件六、总结 前言 在 GLTF 生态中,.bin 文件是 GLTF 格式的重要组成部分,通常与 .gltf 文件一起使用。以下是它们的详细关…...
蓝桥杯(N皇后问题)------回溯法
题目描述 在 NN 的方格棋盘放置了 N 个皇后,使得它们不相互攻击(即任意 2 个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成 45 角的斜线上。你的任务是,对于给定的 N,求出有多少种合法的放置方法…...
Linux系统中关闭Docker服务并禁止其开机自启 、docker 安装目录结构分析 | 【du -sh *】
文章目录 在Linux系统中关闭Docker服务并禁止其开机自启,具体步骤如下:适用于使用 systemd 的系统(如Ubuntu 16.04/CentOS 7等)适用于使用 SysVinit 或 Upstart 的旧版系统其他注意事项示例输出 linux 下 一条命令实现 统计各个目…...
免费下载 | 2025低空经济产业发展报告
低空经济概览 产业链条:低空经济产业链分为上游的低空经济基础设施(如空管系统、飞行基地等)、中游的低空制造(包括无人机、eVTOL、直升机等飞行器的设计、研发、生产)和下游的低空运营及飞行服务。低空经济以低空空域…...
单一职责原则开闭原则其他开发原则
一、单一职责原则(Single Responsibility Principle, SRP) 定义 一个类应该有且仅有一个引起它变化的原因(即一个类只负责一个职责)。 核心思想 高内聚:类的功能高度集中 低耦合:减少不同职责之间的相互影…...
(自用)yolo算法学习
1.难受中,看了教程过后无从下手啊 2.pycharm专业版成功就好 3.安装包时出先问题 (base) PS G:\pycharm\projects\yolo\yolov5> pip install opencv-python>4.1.1 Requirement already satisfied: opencv-python>4.1.1 in g:\anaconda\app\lib\site-packa…...
手机号登录与高并发思考
基础逻辑 一般来说这个验证码登录分为手机号、以及邮箱登录 手机号短信验证,以腾讯云SMS 服务为例: 这个操作无非对后端来说就是两个接口: 一个是获取验证码,这块后端生成6位数字expire_time 去推送到腾讯云sdk ,腾…...
Linux系统管理与编程07:任务驱动综合应用
兰生幽谷,不为莫服而不芳; 君子行义,不为莫知而止休。 [环境] windows11、centos9.9.2207、zabbix6、MobaXterm、Internet环境 [要求] zabbix6.0安装环境:Lamp(linux httpd mysql8.0 php) [步骤] 2 …...