Vue 3 源码层核心原理剖析(完整详解版)
一、Compiler 编译过程解密:多框架实现对比
Vue 3 编译流程深度解析(基于 /packages/compiler-core/src/parse.ts
)
完整编译链条及技术实现:
01、词法分析阶段(Tokenizer)
1. 核心实现机制
Vue 3 编译器采用**有限状态机(Finite State Machine, FSM)**解析模板字符串,核心逻辑位于/packages/compiler-core/src/parse.ts
的parse
函数:
// 解析器入口函数
function parse(content: string, options: ParserOptions = {}): RootNode {// 创建解析上下文const context = createParserContext(content, options)// 获取初始光标位置const start = getCursor(context)// 解析子节点(核心处理逻辑)const children = parseChildren(context, [])// 返回AST根节点return {type: NodeTypes.ROOT,children,loc: getSelection(context, start), // 记录源码位置信息components: [], // 组件集合directives: [], // 指令集合hoists: [], // 静态提升节点imports: [], // 导入声明cached: 0, // 缓存节点计数temps: 0 // 临时变量计数}
}
2. 核心正则表达式
Vue 使用以下正则表达式进行词法分析,识别模板中的关键元素:
// 标准标签名(字母/下划线开头,可包含连字符、点、数字)
const ncname = `[a-zA-Z_][\\-\\.0-9_a-zA-Z]*`// 带命名空间的标签(如<svg:circle>)
const qnameCapture = `((?:${ncname}\\:)?${ncname})`// 开始标签匹配(如<div>)
const startTagOpen = new RegExp(`^<${qnameCapture}`)// 开始标签结束(匹配>或/>)
const startTagClose = /^\s*(\/?)>/// 属性解析(识别属性名、等号、属性值)
const attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/// 结束标签匹配(如</div>)
const endTag = new RegExp(`^<\\/${qnameCapture}[^>]*>`)// 文档类型声明(<!DOCTYPE>)
const doctype = /^<!DOCTYPE [^>]+>/i// 注释节点(<!-- comment -->)
const comment = /^<!\--/// 条件注释(<![if IE]>)
const conditionalComment = /^<!\[/
3. 词法分析处理流程
状态机按以下顺序处理模板内容:
-
标签开闭识别
// 处理开始标签 if (startTagOpen.test(html)) {const startTagMatch = parseStartTag()if (startTagMatch) {handleStartTag(startTagMatch)continue} }// 处理结束标签 if (endTag.test(html)) {const endTagMatch = html.match(endTag)if (endTagMatch) {advance(endTagMatch[0].length)parseEndTag(endTagMatch[1])continue} }
-
属性解析
while (!end(html) &&!(endTag.test(html)) &&!(startTagOpen.test(html)) &&(attr = html.match(attribute)) ) {advance(attr[0].length)match.attrs.push(attr) }
-
文本插值处理 (
{{ value }}
)if (html.indexOf(context.options.delimiters[0]) === 0) {// 解析插值表达式const [full, content] = parseInterpolation(context)nodes.push({type: NodeTypes.INTERPOLATION,content: {type: NodeTypes.SIMPLE_EXPRESSION,content,isStatic: false,constType: ConstantTypes.NOT_CONSTANT},loc: getSelection(context, start)}) }
-
指令识别 (
v-if
,v-for
等)if (/^(v-[A-Za-z0-9-]|:|\.|@|#)/.test(name)) {// 解析指令const match = /(?:^v-([a-z0-9-]+))?(?:(?::|\.|@|#)(\[[^\]]+\]|[^\.]+))?(.+)?$/i.exec(name)if (match) {// 提取指令名、参数、修饰符const dirName = match[1] || (startsWith(name, ':') ? 'bind' : ''const arg = match[2] ? match[2].trim() : undefined// 构建指令节点addDirective(node, dirName, arg, modifiers)} }
-
特殊符号处理
// 处理<!DOCTYPE> if (doctype.test(html)) {advance(html.match(doctype)[0].length)continue }// 处理注释节点 if (comment.test(html)) {const commentEnd = html.indexOf('-->')if (commentEnd >= 0) {advance(commentEnd + 3)continue} }// 处理条件注释 if (conditionalComment.test(html)) {const conditionalEnd = html.indexOf(']>')if (conditionalEnd >= 0) {advance(conditionalEnd + 2)continue} }
4. 状态机工作流程
词法分析的状态转换流程如下:
5. 错误处理机制
状态机包含完善的错误检测:
// 标签嵌套检查
function parseChildren(context, ancestors) {const parent = last(ancestors)while (!isEnd(context, ancestors)) {// ...解析逻辑...}// 检查未闭合标签if (parent && context.source) {emitError(context,ErrorCodes.X_MISSING_END_TAG,parent.loc.start)}
}// 自定义错误类型
export const enum ErrorCodes {X_MISSING_END_TAG = 1, // 缺少结束标签X_MISSING_INTERPOLATION_END, // 缺少插值结束符号X_MISSING_DIRECTIVE_NAME, // 指令名缺失X_MISSING_ATTRIBUTE_VALUE, // 属性值缺失X_INVALID_DIRECTIVE_ARG, // 无效的指令参数// ...20+种错误类型...
}
6. 位置信息追踪
编译器精确记录每个节点的源码位置:
// 获取当前光标位置
function getCursor(context: ParserContext): Position {const { column, line, offset } = contextreturn { column, line, offset }
}// 记录节点位置范围
function getSelection(context: ParserContext,start: Position,end?: Position
): SourceLocation {return {start,end: end || getCursor(context),source: context.originalSource.slice(start.offset, context.offset)}
}
7. 性能优化策略
-
增量解析:使用
advance()
逐步消费模板字符串function advance(context: ParserContext, numberOfChars: number) {const { source } = context// 更新行列计数advancePositionWithMutation(context, source, numberOfChars)// 截取剩余字符串context.source = source.slice(numberOfChars) }
-
预扫描优化:快速跳过大型文本节点
if (textEnd > 0) {// 批量处理文本内容const text = context.source.slice(0, textEnd)advance(context, textEnd)return text }
-
正则表达式优化:所有正则使用
^
开头锚点确保高效匹配
这种基于有限状态机的词法分析设计,使Vue 3编译器能在O(n)时间复杂度内完成模板解析,同时保持精确的错误定位能力,为后续的语法解析和优化阶段奠定坚实基础。
02、语法解析阶段(Parser)
使用递归下降算法构建AST,核心逻辑:
function parseChildren(context: ParserContext, ancestors: ElementNode[]): TemplateChildNode[] {const nodes: TemplateChildNode[] = []while (!isEnd(context, ancestors)) {const s = context.sourcelet node: TemplateChildNode | undefinedif (startsWith(s, context.options.delimiters[0])) {// 解析插值表达式 {{ value }}node = parseInterpolation(context)} else if (s[0] === '<') {// 解析元素标签if (/[a-z]/i.test(s[1])) {node = parseElement(context, ancestors)}}if (!node) {// 解析纯文本内容node = parseText(context)}pushNode(nodes, node)}return nodes
}
03、语义优化技术
Vue 3特有的编译时优化:
- 静态节点提升(hoistStatic):将静态节点提取到渲染函数外部,避免重复创建
// 优化前
function render() {return h('div', [h('span', '静态内容'),h('p', dynamicValue)])
}// 优化后
const _hoisted = h('span', '静态内容')
function render() {return h('div', [_hoisted,h('p', dynamicValue)])
}
- 补丁标志(patchFlag):使用位运算标记动态节点类型
// patchFlags 位掩码定义
export const enum PatchFlags {TEXT = 1, // 动态文本内容CLASS = 1 << 1, // 动态class绑定STYLE = 1 << 2, // 动态style绑定PROPS = 1 << 3, // 动态非class/style属性FULL_PROPS = 1 << 4, // 需要完整props比较HYDRATE_EVENTS = 1 << 5, // 带事件监听器STABLE_FRAGMENT = 1 << 6, // 稳定片段(子节点顺序不变)KEYED_FRAGMENT = 1 << 7, // 带key的片段UNKEYED_FRAGMENT = 1 << 8, // 无key的片段NEED_PATCH = 1 << 9, // 需要非props补丁DYNAMIC_SLOTS = 1 << 10 // 动态插槽
}
- 缓存事件处理程序(cacheHandler):避免重复创建事件处理器
// 优化前
function render() {return h('button', { onClick: () => handler() })
}// 优化后
const _cache = {}
function render() {return h('button', { onClick: _cache[1] || (_cache[1] = () => handler())})
}
Vue 2 编译实现深度对比
架构级差异:
1. 解析器实现差异
Vue 2 使用基于正则的字符串处理(/src/compiler/parser/index.js
):
// Vue 2 解析器核心
parseHTML(template, {start(tag, attrs, unary) {// 处理开始标签const element = createASTElement(tag, attrs)processElement(element)},end() {// 处理结束标签closeElement()},chars(text) {// 处理文本内容handleText(text)},comment(text) {// 处理注释handleComment(text)}
})
Vue 3 使用状态机驱动的位运算(/packages/compiler-core/src/parse.ts
):
// 文本解析模式状态枚举
const enum TextModes {DATA, // 默认模式RCDATA, // <textarea> 内容模式RAWTEXT, // <style>,<script> 模式CDATA, // <![CDATA[ 内容ATTRIBUTE_VALUE // 属性值解析模式
}// 状态转换逻辑
function parseTag(context: ParserContext, type: TagType): ElementNode {const start = getCursor(context)const match = /^<\/?([a-z][^\t\r\n\f />]*)/i.exec(context.source)!const tag = match[1]advanceBy(context, match[0].length)advanceSpaces(context)// 属性解析状态处理const props = parseAttributes(context, type)// 其他状态处理...
}
2. AST结构差异
Vue 2 AST节点(简化):平铺式节点结构
{type: 1, // 元素节点tag: 'div',attrsList: [{ name: 'class', value: 'container' }],children: [{ type: 2, text: '{{ message }}', expression: '_s(message)' }]
}
Vue 3 AST节点(增强):树形结构+动态标记
interface ElementNode extends Node {type: NodeTypes.ELEMENTtag: stringtagType: ElementTypesprops: Array<AttributeNode | DirectiveNode>children: TemplateChildNode[]codegenNode: CodegenNode | undefined// 新增优化字段patchFlag: numberdynamicProps: string[] | nullisStatic: boolean
}
React JSX 编译原理详解
Babel 转换流程:
// JSX 源代码
<div className="container" onClick={handleClick}>{message}<Button>提交</Button>
</div>// 经babel转换后(React 16)
React.createElement("div",{ className: "container", onClick: handleClick },message,React.createElement(Button, null, "提交")
)
编译时优化:
// React 17+ 新转换
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
_jsxs("div", {className: "container",onClick: handleClick,children: [message,_jsx(Button, { children: "提交" })]
});
与Vue的核心差异:
- 无静态提升:每次渲染都创建完整的VNode树
- 无补丁标志:依赖Virtual DOM的全量diff
- 无编译时优化:JSX直接转换为运行时函数调用
- 动态处理:所有优化在运行时完成(如React.memo)
编译时优化尝试:
// React Forget编译器(实验性)
function Component(props) {"use no forget"const [count, setCount] = useState(0)const doubled = count * 2 // 自动记忆化return <div>{doubled}</div>
}
二、响应式系统实现:多框架深度对比
Vue 3 响应式系统(Proxy实现)
核心架构:
生产级实现细节:
// 响应式入口(/packages/reactivity/src/reactive.ts)
function reactive(target: object) {// 避免重复代理if (target[ReactiveFlags.RAW] && !(isReadonly && target[ReactiveFlags.IS_REACTIVE])) {return target}// 查找现有代理const existingProxy = proxyMap.get(target)if (existingProxy) return existingProxy// 创建代理const proxy = new Proxy(target,baseHandlers)proxyMap.set(target, proxy)return proxy
}// 数组方法重写(/packages/reactivity/src/baseHandlers.ts)
const arrayInstrumentations: Record<string, Function> = {}
;['push', 'pop', 'shift', 'unshift', 'splice'].forEach(key => {arrayInstrumentations[key] = function (...args: any[]) {pauseTracking() // 暂停依赖收集const res = (this as any)[key].apply(this, args)resetTracking() // 恢复依赖收集return res}
})
依赖收集系统:
// 依赖收集器(/packages/reactivity/src/effect.ts)
class ReactiveEffect {deps: Dep[] = [] // 依赖此effect的所有deprun() {try {this.parent = activeEffectactiveEffect = thisshouldTrack = true// 执行前清空依赖cleanupEffect(this)// 执行副作用函数return this.fn()} finally {activeEffect = this.parentshouldTrack = lastShouldTrackthis.parent = undefined}}
}// 依赖收集(track函数)
function track(target: object, type: TrackOpTypes, key: unknown) {if (!shouldTrack || activeEffect === undefined) returnlet depsMap = targetMap.get(target)if (!depsMap) {targetMap.set(target, (depsMap = new Map()))}let dep = depsMap.get(key)if (!dep) {depsMap.set(key, (dep = createDep()))}trackEffects(dep)
}function trackEffects(dep: Dep) {if (!activeEffect) return// 建立双向依赖关系dep.add(activeEffect)activeEffect.deps.push(dep)
}
生产级优化:
1.嵌套代理缓存
2.数组方法拦截
3.调度器批量更新
Vue 2 响应式系统深度解析
实现原理:
// 响应式入口(/src/core/observer/index.js)
class Observer {constructor(value) {this.value = valuethis.dep = new Dep()def(value, '__ob__', this)if (Array.isArray(value)) {// 数组响应式处理augment(value, arrayMethods, arrayKeys)this.observeArray(value)} else {// 对象响应式处理this.walk(value)}}walk(obj) {const keys = Object.keys(obj)for (let i = 0; i < keys.length; i++) {defineReactive(obj, keys[i])}}
}// 属性劫持
function defineReactive(obj, key, val) {const dep = new Dep()// 处理嵌套对象let childOb = observe(val)Object.defineProperty(obj, key, {enumerable: true,configurable: true,get: function reactiveGetter() {const value = valif (Dep.target) {dep.depend() // 收集依赖if (childOb) {childOb.dep.depend() // 嵌套对象依赖收集if (Array.isArray(value)) {dependArray(value) // 数组依赖收集}}}return value},set: function reactiveSetter(newVal) {if (newVal === value) returnval = newValchildOb = observe(newVal) // 新值响应式处理dep.notify() // 触发更新}})
}
局限性解决方案:
// Vue.set 实现(/src/core/observer/index.js)
function set(target, key, val) {// 处理数组if (Array.isArray(target) {target.length = Math.max(target.length, key)target.splice(key, 1, val)return val}// 处理对象if (hasOwn(target, key)) {target[key] = valreturn val}// 新增属性const ob = target.__ob__if (!ob) {target[key] = valreturn val}// 将新属性转为响应式defineReactive(ob.value, key, val)ob.dep.notify() // 手动触发更新return val
}
局限性对比:
特性 | Vue2 | Vue3 |
---|---|---|
属性增删检测 | ❌ 需Vue.set | 原生支持 |
数组索引变更 | ❌需重写方法 | 原生支持 |
性能开销 | O(n) 属性级劫持 | O(1) 对象级代理 |
React 响应式系统原理
Hooks 实现机制:
// useState 简化实现(模拟 React 源码)
let hookStates = []
let hookIndex = 0
let scheduleUpdate = nullfunction useState(initialState) {const currentIndex = hookIndexhookStates[currentIndex] = hookStates[currentIndex] || (typeof initialState === 'function' ? initialState() : initialState)const setState = (newState) => {// 状态对比(使用 Object.is)if (Object.is(hookStates[currentIndex], newState)) return// 处理函数式更新hookStates[currentIndex] = typeof newState === 'function' ? newState(hookStates[currentIndex]) : newState// 触发重新渲染scheduleUpdate()}hookIndex++return [hookStates[currentIndex], setState]
}// useEffect 简化实现
function useEffect(callback, deps) {const currentIndex = hookIndexconst [lastDeps, cleanup] = hookStates[currentIndex] || [null, null]// 依赖比较const hasChanged = !deps || !lastDeps || deps.some((dep, i) => !Object.is(dep, lastDeps[i]))if (hasChanged) {// 执行清理函数if (cleanup && typeof cleanup === 'function') cleanup()// 异步执行effectPromise.resolve().then(() => {const cleanupFn = callback()hookStates[currentIndex] = [deps, cleanupFn]})}hookIndex++
}
更新机制对比:
特性 | Vue 3 | React |
---|---|---|
更新粒度 | 组件内元素级 | 组件级 |
依赖跟踪 | 自动 | 手动(依赖数组) |
状态变更检测 | Proxy 拦截 | Object.is 比较 |
批量更新 | 自动(nextTick) | 自动(事件处理中) |
异步更新队列 | 有 | 有 |
嵌套更新处理 | 自动防止无限循环 | 最大更新深度限制 |
Vue:自动依赖追踪,精确更新
React:组件树重渲染+差异比对
优化策略:
Vue:响应式依赖追踪
React:memo/shouldComponentUpdate
三、跨框架编译优化策略对比
优化策略 | Vue 3 | Vue 2 | React |
---|---|---|---|
静态提升 | ✅ 提取静态节点到渲染函数外部 | ❌ 无 | ❌ 无 |
补丁标志 | ✅ 位运算标记动态元素 (PatchFlags) | ❌ 无 | ❌ 无 |
事件缓存 | ✅ 自动缓存事件处理器 | ❌ 无 | ❌ 无 |
树结构优化 | ✅ Block Tree 减少动态节点遍历 | ❌ 递归全量diff | ✅ Fiber架构增量渲染 |
常量折叠 | ✅ 编译时计算静态表达式 | ⚠️ 有限支持 | ❌ 无 |
按需更新 | ✅ 元素级精确更新 | ⚠️ 组件级 | ⚠️ 组件级 |
SSR优化 | ✅ 同构hydration + 静态内容直出 | ⚠️ 基础SSR支持 | ✅ Streaming SSR + Suspense |
代码拆分 | ✅ 基于路由的异步组件 | ⚠️ 异步组件 | ✅ React.lazy + Suspense |
Tree Shaking | ✅ 良好支持 | ⚠️ 有限支持 | ✅ 完善支持 |
源映射支持 | ✅ 完整模板到渲染函数的source map | ⚠️ 部分支持 | ✅ JSX到JS的source map |
四、编译与响应式协同工作原理
Vue 3 运行时完整工作流:
协同优势详解:
-
编译时信息利用:
- 编译器识别静态节点,减少运行时比较
- 补丁标志指导运行时diff算法优化路径
// 基于patchFlag的优化diff if (patchFlag & PatchFlags.CLASS) {// 只需更新classupdateClass(oldVNode, newVNode) } else if (patchFlag & PatchFlags.STYLE) {// 只需更新styleupdateStyle(oldVNode, newVNode) } else if (patchFlag & PatchFlags.TEXT) {// 只需更新文本内容updateText(oldVNode, newVNode) }
-
响应式精准更新:
- 依赖收集系统建立数据与视图的精确关联
- 避免不必要的组件重新渲染
// 组件更新条件(/packages/runtime-core/src/componentRenderUtils.ts) shouldUpdateComponent(prevVNode: VNode,nextVNode: VNode,optimized?: boolean ): boolean {// 通过patchFlag快速判断if (nextVNode.patchFlag > 0) {const flag = nextVNode.patchFlagif (flag & PatchFlags.DYNAMIC_SLOTS) {return true}if (flag & PatchFlags.FULL_PROPS) {// 需要完整props比较} else {// 仅检查特定props}} }
-
内存优化策略:
- 静态节点提升减少内存分配
- 事件缓存减少函数对象创建
- 组件实例复用策略
五、框架设计哲学对比
设计维度 | Vue 3 | React |
---|---|---|
核心思想 | 渐进增强 + 编译优化 | 函数式编程 + 不可变数据 |
更新机制 | 自动依赖追踪 + 精准更新 | 状态驱动 + 虚拟DOM diff |
模板系统 | 声明式模板 + 指令系统 | JSX(JavaScript 语法扩展) |
状态管理 | 响应式自动依赖收集 | 手动状态管理 + 依赖数组 |
学习曲线 | 模板导向,较低门槛 | JSX导向,较高抽象能力要求 |
性能策略 | 编译时优化为主 + 运行时辅助 | 运行时优化为主 |
类型支持 | TypeScript 优先 | TypeScript 完善支持 |
移动端支持 | Weex/NativeScript | React Native |
未来方向 | Vapor模式(更细粒度响应式) | React Forget(编译优化) |
SSR架构 | Nuxt.js + Vite | Next.js + React Server Components |
六、源码学习指南
Vue 3 核心源码路径:
-
编译器入口:
/packages/compiler-core/src/compile.ts
baseCompile
函数:完整编译流程入口transform
模块:AST转换优化核心
-
解析器实现:
/packages/compiler-core/src/parse.ts
baseParse
函数:模板解析入口parseElement
:元素节点解析逻辑parseInterpolation
:插值表达式解析
-
响应式系统:
/packages/reactivity/src/
reactive.ts
:响应式入口effect.ts
:副作用管理核心baseHandlers.ts
:Proxy处理器实现collectionHandlers.ts
:集合类型处理器
-
运行时核心:
/packages/runtime-core/src/
renderer.ts
:渲染器实现componentRenderUtils.ts
:组件渲染工具scheduler.ts
:异步调度队列
React 核心源码路径:
-
调和器:
/packages/react-reconciler/src/
ReactFiberWorkLoop.js
:Fiber调度核心ReactFiberBeginWork.js
:Fiber节点处理ReactFiberCompleteWork.js
:Fiber完成工作
-
Hooks系统:
/packages/react/src/
ReactHooks.js
:Hook入口Hooks.js
:Hook实现核心
-
JSX运行时:
/packages/react/src/jsx/
ReactJSX.js
:JSX元素创建ReactJSXElementValidator.js
:JSX元素验证
对比学习建议:
-
编译器设计对比:
- Vue 的
transformElement
vs Babel 的transform-react-jsx
- Vue 的 AST 优化遍历 vs React 的运行时优化
- Vue 的
-
响应式实现对比:
- Vue 的
track/targetMap
依赖收集 vs React 的useState/useEffect
依赖数组 - Vue 的响应式更新调度 vs React 的 Fiber 调度算法
- Vue 的
-
渲染优化对比:
- Vue 的 Block Tree 机制 vs React 的 Fiber 树
- Vue 的静态节点提升 vs React 的
React.memo
性能优化本质差异:
Vue:通过编译获取模板语义信息,在运行时做最少的工作
React:通过虚拟DOM和差异比对,在运行时做智能的更新决策调试技巧:
- 使用 Vue 的
@vue/compiler-sfc
单独测试编译输出- 使用 React 的
__PROFILE__
标记进行性能分析- 通过源码映射(sourcemap)在浏览器调试原始代码
总结:现代框架演进趋势
-
编译与运行时的深度融合
- Vue:Vapor 模式(实验性)将更多逻辑移至编译时
// Vapor 模式示例(概念) const __vapor__ = compile(`<div>{{ msg }}</div>`) function setup() {const msg = ref('Hello')return __vapor__({ msg }) }
- React:React Forget 编译器自动记忆化
- Svelte:激进编译策略生成极简运行时
-
响应式范式的统一
- Vue:保持基于 Proxy 的响应式
- React:探索 Signal 基础原语
// React Signals 提案(实验性) const count = createSignal(0) const double = createMemo(() => count.value * 2) return <div>{double.value}</div>
-
全栈架构的整合
- Vue:Vite + SSR + Pinia 一体化
- React:Next.js + Server Components + Turbopack
- 共同点:服务端组件、岛屿架构(Islands Architecture)
-
类型系统的演进
- Vue:
<script setup>
+ TypeScript + Volar - React:TypeScript 优先 + 更严格的类型检查
- 共同点:提升大型应用可维护性
- Vue:
-
性能基准的持续优化
- Vue:优化内存占用(静态提升)
- React:优化交互响应(并发渲染)
- 共同目标:达到接近原生性能的Web体验
码字不易,各位大佬点点赞呗
相关文章:
Vue 3 源码层核心原理剖析(完整详解版)
一、Compiler 编译过程解密:多框架实现对比 Vue 3 编译流程深度解析(基于 /packages/compiler-core/src/parse.ts) 完整编译链条及技术实现: #mermaid-svg-S8ScpxdjkcJv0YWT {font-family:"trebuchet ms",verdana,ari…...
数据库操作-MySQL-4(JDBC编程)
JDBC:通过Java代码操作mysql数据库,数据库会提供一些API供我们调用 MySQL、Oracle、等API有差异,但是Java统一了所有接口,即JDBC; 原始api-驱动包(类似转接头)-统一的api-Java 驱动包࿱…...
Linux打开.img镜像文件
kparkx 可以查看和修改img文件的内容 1.安装kparkx 1.安装 kpartx sudo apt-get update sudo apt-get install kpartx2.使用kpartx映射镜像文件 假设镜像文件名为 example.img ,以下命令会将其分区映射到 dev/mapper/ sudo kpartx -av example.img• -a表示添加…...
【FAQ】HarmonyOS SDK 闭源开放能力 —Account Kit(5)
1.问题描述: 集成华为一键登录的LoginWithHuaweiIDButton, 但是Button默认名字叫 “华为账号一键登录”,太长无法显示,能否简写成“一键登录”与其他端一致? 解决方案: 问题分两个场景: 一、…...

【科研绘图系列】R语言绘制论文组合图形(multiple plots)
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍加载R包数据下载导入数据数据预处理画图1画图2画图3画图4画图5系统信息介绍 这篇文章详细介绍了如何使用R语言进行科研绘图,特别是绘制论文组合图形(multiple plots)。文章从数…...

springMVC-9数据格式化
数据格式化 学习目标: 理解在我们提交数据(比如表单时),SpringMVC怎样对提交的数据进行转换和处理的 Spring MVC 上下文中内建了很多转换器,可完成大多数 Java 类型的转换工作。 基本数据类型可以和字符串之间自动完成转换 应用实例-页面…...
Kafka 和Redis 在系统架构中的位置
Kafka 位置:位于应用层和数据存储层之间,作为消息队列和数据传输中间件。作用: 数据收集与传输:收集应用层产生的数据,传输到后端数据存储系统。消息队列:实现应用层各服务之间的异步通信和解耦。与应用层…...
【Spring AI】如何实现文生图功能
在人工智能与软件开发深度融合的当下,Spring AI 作为构建 AI 驱动应用的有力框架,能够便捷集成各类 AI 能力。 文生图技术可将文本描述转化为图像,极具应用价值。接下来,我给大家详细讲解一下如何使用 Spring AI 调用文生图功能。…...
【ISAQB大纲解读】Kafka消息总线被视为“自下而上设计”?
Kafka消息总线被视为“自下而上设计”的典型案例,核心在于其设计路径和演化逻辑完全符合自下而上方法的本质特征: 自下而上设计的核心逻辑 #mermaid-svg-pDSqW0S2h0bj15iN {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16…...

ISBN书号查询接口如何用PHP实现调用?
一、什么是ISBN书号查询接口 ISBN数据查询接口是一项图书信息查询服务。它基于全球通用的ISBN编码系统,帮助用户快速获取图书的详细信息,包括书名、作者、出版社、出版时间、价格、封面等关键字段。 该接口广泛应用于电商平台、图书馆管理系统、二手书…...
什么是 Docker Compose 的网络(network),为什么你需要它,它是怎么工作的
Docker Compose 的网络就是:让多个容器之间能像“连上同一个局域网”一样互相通信,不用管 IP,用服务名就能访问彼此。 就像家里连接到同一个 WiFi 的手机、电脑、电视,它们都能互相发现对方,Docker 里的容器也是一样 …...
嵌入式Linux 期末复习指南(上)
鉴于互联网上针对本科目相关复习视频及资料过少, 撰写本篇期末复习指南用作期末复习知识点扫盲,以应对本科期末考试及格之用。 由于任课老师并透露考试范围或任何有关试卷的相关信息,本篇指南基于教材、上机实验报告及作者经验编写࿰…...
SpringBoot3.2新特性:JdbcClient
文章目录 一、简介二、使用1、支持隐式位置参数2、通过索引设置位置参数3、支持 Name / Value 对命名参数4、通过 Map 设置命名参数5、使用 JdbClient 执行更新操作6、使用示例 参考资料 一、简介 Spring 6.1 中新添加了 JdbcClient 接口,它提供了 Fluent 风格的 A…...
Dify:启动 Web 服务的详细指南
1. 进入 web 目录 cd web解释: cd 是 “change directory” 的缩写,用于切换当前工作目录。您需要进入项目的 web 目录,这是前端代码所在的位置。在这个目录下,您可以执行构建和启动 Web 服务的相关命令。 2. 安装依赖 pnpm in…...
3.1 HarmonyOS NEXT分布式数据管理实战:跨设备同步、端云协同与安全保护
HarmonyOS NEXT分布式数据管理实战:跨设备同步、端云协同与安全保护 在万物互联的时代,数据的跨设备流转与安全共享是全场景应用的核心需求。HarmonyOS NEXT通过分布式数据管理技术,实现了设备间数据的实时同步与端云协同,为开发…...

Aop + 注解实现数据字典类型转换 EasyExcel导出
Aop 注解 实现数据字典类型转换 文章目录 Aop 注解 实现数据字典类型转换一、基础方式✅字典转换简介👉实现步骤✅ 1. 定义自定义注解Dict ✅ 2. 定义查询字典项的两个方法✅ 3. 定义Aop拦截我们查询的方法✅ 4. VO映射类✅ 5. Controller层✅ 6. serviceImpl✅ 7. …...
Python 元组方法全集详解
Python 元组方法全集详解 在 Python 中,元组(tuple)是不可变序列类型,因此支持的操作比列表少。以下是元组支持的所有方法和操作: 一、元组核心方法 1. 创建元组 # 标准创建 t = (1, 2, 3) # (1, 2, 3) t = tuple(...
Selenium 中 JavaScript 点击操作的原理及应用
在 Selenium 中使用 JavaScript 执行点击操作(如 driver.execute_script("arguments[0].click();", element))的原理涉及 WebDriver 架构、浏览器事件机制以及 JavaScript 对 DOM 的直接操作,以下是详细解释: 1. Selen…...

Xilinx超过256m bit flash固件跳转失败问题
问题描述 按照 链接: Xilinx 7系列fpga在线升级和跳转 这个方式跳转失败 问题排查 进一步排查现象如下 上面这个现象呈现出明显的以16m为周期的规律。感觉很大概率是因为flash超过了16m(256bit)导致的地址越界问题。另外我在CSDN上也找到类似的问题…...

SpringCloud 分布式锁Redisson锁的重入性与看门狗机制 高并发 可重入
可重入 Redisson 的锁支持 可重入性,这意味着同一个线程在获取锁后,如果再次尝试获取该锁,它可以成功地获得锁,而不会被阻塞。 每次一个线程成功获取锁后,它的持有次数会增加。当线程再次获取该锁时,Redi…...

02 APP 自动化-Appium 运行原理详解
环境搭建见 01 APP 自动化-环境搭建 文章目录 一、Appium及Appium自动化测试原理二、Appium 自动化配置项三、常见 ADB 命令四、第一个 app 自动化脚本 一、Appium及Appium自动化测试原理 Appium 跨平台、开源的 app 自动化测试框架,用来测试 app 应用程序&#x…...

由docker引入架构简单展开说说技术栈学习之路
想象一下,你开了一家线上小卖部(单机版),突然爆单了怎么办?别急,技术架构的升级打怪之路,可比哆啦A梦的口袋还神奇! 第1关:单枪匹马的创业初期(单机架构&…...

linux 1.0.5
环境变量到底是什么 也就是windows上面的环境变量 就是这个东东,用户变量和系统变量,那这些到底是啥呢? 主包只是用过,配置来配置去的,就是不知道是啥意思 windows上面的环境变量 windows的ls命令是dir 输入calc可有…...

强化学习的前世今生(五)— SAC算法
书接前四篇 强化学习的前世今生(一) 强化学习的前世今生(二) 强化学习的前世今生(三)— PPO算法 强化学习的前世今生(四)— DDPG算法 本文为大家介绍SAC算法 7 SAC 7.1 最大熵强化…...
SQL进阶之旅 Day 8:窗口函数实用技巧
【SQL进阶之旅 Day 8】窗口函数实用技巧 在现代数据库开发中,处理复杂的业务逻辑和大规模数据时,仅仅依靠传统的GROUP BY和JOIN操作已经无法满足需求。**窗口函数(Window Function)**作为SQL标准的一部分,为开发者提供…...

生成对抗网络(GAN)基础原理深度解析:从直观理解到形式化表达
摘要 本文详细解析 生成对抗网络(GAN) 的 核心原理,从通俗类比入手,结合印假钞与警察博弈的案例阐述生成器 与 判别器 的对抗机制;通过模型结构示意图,解析 噪声采样、样本生成 及判别流程;基于…...
ubuntu 安装redis-6.2.9 源码安装和相关配置详解
目录 1 查看redis 软件列表 2 操作系统信息 3 redis软件下载并编译安装 4 redis 配置文件 5 启动redis 6 redis登录测试 7 设置redis开机启动 8 redis 配置详解 1 查看redis 软件列表 https://download.redis.io/releases/ 2 操作系统信息 rootu24-redis-120:~# cat /…...
c++之数组
目录 C数组基础概念 数组常见操作 二维数组定义与初始化 二维数组遍历方法 二维数组与函数 C数组基础概念 数组是C中用于存储相同类型元素的连续内存结构。通过索引访问元素,索引从0开始。数组大小必须在编译时确定,属于静态数据结构。 #include &…...
torch.distributed.launch 、 torchrun 和 torch.distributed.run 无法与 nohup 兼容
问题现象: 使用nohup 启动torch的分布式训练后, 由于ssh断开与服务器的连接, 导致训练过程出错: WARNING:torch.distributed.elastic.agent.server.api:Received 1 death signal, shutting down workers WARNING:torch.distribu…...
[SC]C++ 中 struct vs. class 的唯一区别
SystemC中 struct vs. class 的唯一区别 一、背景: 在 SystemC 示例里你会常看到这样的写法:SC_MODULE(Top) {// … ports, signals, 进程注册 … };而如果你展开宏 SC_MODULE(Top),它本质上就是:struct Top : sc_core::sc_module {// public:// Top(sc_core::sc_module_…...