Vue3响应式核心:从effect源码看懂依赖收集与派发更新
1. 为什么我要把 effect 源码当作 Vue3 响应式的敲门砖很多人学 Vue3 源码上来就冲 reactive、ref 的实现结果读完 get 和 set 的拦截逻辑还是懵的。原因很简单reactive 和 ref 只是响应式数据的壳真正让数据变化能驱动视图更新、计算属性重算、watch 回调触发的是背后那套依赖收集和派发更新的机制。而effect 就是这套机制的心脏。不管你是用ref(0)声明了一个计数器还是在template里写了{{ state.count }}编译器和运行时最终都会把它们收敛成 effect 的注册和执行。换句话说如果你能从头到尾读懂effect这个函数干了什么Vue3 响应式系统的一半就算真正拿下了。这篇文章我会直接从 Vue3 源码中effect相关的核心逻辑出发一层层拆开它的执行过程解释它为什么在首次执行收集依赖、为什么依赖变化后会自动重新执行、又为什么会有 scheduler、stop、cleanup 这些看起来绕来绕去的设计。文中涉及的部分逻辑我会做适当精简保留主干去掉与当前主题无关的分支方便你抓住主线。适合的读者是这样一批人已经用过 Vue3 写过几个项目知道ref、computed、watch的大概用法但一直没搞懂数据变了函数怎么就自动跑了这件事。如果你还没写过 Vue3建议先动手写两个组件再来读这篇文章否则源码里的每一步对你来说都是抽象概念。2. effect 在 Vue3 源码中的位置一个桶模型的前世今生2.1 响应式系统的数据流全景在拆 effect 源码之前先建立整体认知。Vue3 的响应式系统核心代码主要集中在packages/reactivity/src目录下里面有几个关键文件reactive.ts提供 reactive 和 readonly、ref.ts提供 ref 和 computed 的基础、computed.ts计算属性、effect.ts依赖收集与派发更新的核心、baseHandlers.tsProxy 的 get/set 拦截器。你如果把整个响应式系统的运行过程画成一条线它是这样的你调用reactive(obj)Vue 用 Proxy 包住原始对象返回一个代理对象。任何对代理对象属性的读取get都会触发track函数——把当前正在运行的 effect 记录到该属性的依赖集合中。任何对代理对象属性的修改set都会触发trigger函数——找到所有依赖这个属性的 effect然后逐个执行它们。这里的关键是第 2 步和第 3 步之间必须有一个当前正在运行的 effect概念。没有这个概念get 拦截器就不知道该把依赖记录到谁头上。而effect函数的职责就是启动一个副作用任务并且在它运行期间标记自己为当前活跃任务。2.2 一个最简化的桶模型你可以把依赖收集机制想象成一个桶模型一个targetMap是个 WeakMapkey 是响应式对象value 是该对象对应的依赖 Map。这个依赖 Map 的 key 是属性名value 是一个 Set存放所有依赖该属性的 effect。伪代码表示就是type Dep SetReactiveEffect type KeyToDepMap Mapany, Dep const targetMap new WeakMapany, KeyToDepMap()为什么要用 WeakMap 而不用 Map因为 WeakMap 的 key 是弱引用当响应式对象本身不再被任何地方引用时它就可以被垃圾回收依赖集合也会随之消失避免内存泄漏。这是我读源码时觉得设计很妙的一个点很多文章往往一句带过但实际面试问Vue3 里为什么用 WeakMap 做依赖映射时答案是精准的为了能让不再使用的响应式对象连同它的依赖集合一起被 GC 回收。effect函数做的核心事情就是向这个桶里添加自己并在依赖被触发时从桶里取出自己重新执行。所以读懂effect源码本质上就是读懂这个桶的存取规则。3. effect 函数主流程拆解从调用到返回的每一步3.1 入口函数 effect 的签名与返回值Vue3 源码中effect函数的入口大概是这样的我按源码主干做了保留忽略部分类型细节export function effectT any(fn: () T, options?: ReactiveEffectOptions): ReactiveEffectT { if ((fn as ReactiveEffect).effect instanceof ReactiveEffect) { fn (fn as ReactiveEffect).effect.fn } const _effect new ReactiveEffect(fn) if (options) { extend(_effect, options) if (options.scope) recordEffectScope(_effect) } if (!options || !options.lazy) { _effect.run() } const runner _effect.run.bind(_effect) as ReactiveEffectRunner runner.effect _effect return runner }这里有几个容易被忽略的细节第一effect返回的不是原始副作用函数而是一个runner——它是_effect.run的绑定函数。这意味着你可以直接调用runner()手动触发这个副作用也可以从runner.effect拿回内部 effect 实例做精细控制比如停止它。第二options.lazy决定了是否立即执行。默认情况下effect(fn)创建完 InternalEffect 后立刻执行一次 fn如果传了{ lazy: true }它不会立即执行而是等你手动调用 runner。第三如果你传入的 fn 本身已经是一个 effect 的 fn即存在fn.effect指向某个 ReactiveEffect 实例它会自动解包避免出现 effect 嵌套 effect 时重复包装的情况。这个设计在做 effect 透传时很有用。第四recordEffectScope涉及 effectScope 的概念这是 Vue3 用于批量管理副作用生命周期的机制底层维护了一个当前全局的 activeScope如果配置了 scope就把当前 effect 记录进去方便在scope.stop()时统一中止所有 effect。3.2 ReactiveEffect 类的核心结构现在看核心类的定义。源码中的 ReactiveEffect 是一个 class但 Vue3 里对依赖收集和派发更新的主路径做了大版本迭代——3.2 之前使用栈结构effectStack管理嵌套 effect3.2 之后切换为activeEffect单一指针加track/trigger内在依赖位点的方式。我先讲新版本的设计因为这更贴近最新的 Vue33.4/3.5行为。export class ReactiveEffectT any { fn: () T scheduler: EffectScheduler | null null active true deps: Dep[] [] onStop?: () void constructor(fn: () T, scheduler: EffectScheduler | null null) { this.fn fn this.scheduler scheduler } run() { if (!this.active) { return this.fn() } return this.runEffect() } stop() { if (this.active) { cleanupEffect(this) this.active false if (this.onStop) { this.onStop() } } } }这里有几个字段的含义需要在继续往下读之前讲明白fn你传给 effect 的副作用函数本身。scheduler如果存在触发更新时不会直接调用 fn而是调用 scheduler由 scheduler 决定什么时候以及如何重新执行 fn。这是 computed、watch 异步更新、组件渲染调度的关键机制。active标记 effect 是否处于激活状态stop 之后变 false之后的 trigger 不再触发它。deps记录当前 effect 被哪些依赖集合Dep包含过用于 cleanup 时把自己从所有依赖中删除。3.3 首次 run 时发生了什么effect(fn)默认情况下会调用_effect.run()这是整个响应式系统链条中最重要的一步。run的执行逻辑可以简化成run() { const prevEffect activeEffect try { activeEffect this return this.fn() } finally { activeEffect prevEffect } }这里做的事情可以用一句话概括在调用副作用函数前把全局的activeEffect指针指向当前 effect等函数执行完再恢复之前的值。为什么这样设计因为当副作用函数内部读取响应式属性时会触发代理的 get 拦截器拦截器内部调用track(target, type, key)而track函数需要知道当前到底谁在依赖这个属性。这个回答就藏在activeEffect这个全局指针里。你可能会问为什么用单一指针而不是数组栈Vue3 在 3.2 之前确实是栈结构但后来优化为单一指针加我在执行期间如果嵌套 effect就自动暂停外层收集的方式。具体到嵌套场景外层 effect 执行到一半内层 effect 调用 run会把 activeEffect 替换成内层内层结束后 restore 回外层。所以读源码时如果你看到关于栈的旧文章不必困惑那是历史版本。首次 run 的完整过程其实是三件事的连环activeEffect this设置全局指针。执行副作用函数 fn函数内部每读取一个响应式属性就触发一次track把当前 effect 加入该属性的依赖集合。fn 执行完毕activeEffect恢复原值。这个首次执行过程有个学名叫建立依赖它跟经典 React 函数式组件首次渲染收集 hooks 依赖的思路有相似之处但 Vue 的粒度更细——它是属性级的依赖不像 hooks 是组件级的依赖。4. track 依赖收集effect 如何被塞进桶里4.1 track 执行流程track函数在 Vue3 中实际是trackEffects这个更底层的函数核心逻辑如下export function track(target: object, type: TrackOpTypes, key: unknown) { if (!shouldTrack || activeEffect null) { return } let 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, undefined) }track的三步走是取出 target 对应的 depsMap不存在就新建。取出 key 对应的 dep一个 Set不存在就新建。调用trackEffects把当前 effect 加入 dep。4.2 trackEffects 里的两个关键细节export function trackEffects(dep: Dep, debuggerEventExtraInfo?: DebuggerEventExtraInfo) { if (dep.get(activeEffect!) undefined) { dep.set(activeEffect!, activeEffect!.id) ;(activeEffect!.deps).push(dep) } }新版源码中dep不再是 Set而是 Map——key 是 effect 实例value 是 effect.id。为什么要这么改主要是为了兼容自引用场景的性能检查以及更精确地识别依赖是否已经存在。正常理解时你可以把 dep 当作 Set 用逻辑等价。注意这里有两个维护方向的动作dep记录 effect表示这个属性依赖了哪个副作用。effect.deps记录 dep表示这个副作用被哪些依赖集合记录过。为什么要反向维护因为当你调用stop()停止一个 effect 时需要把该 effect 从所有依赖集合里删除否则后续属性变更时trigger 查不到已停止的 effect留下脏数据还会造成内存泄漏。反向记录就是为了让清理操作能从 effect 出发快速找到所有需要清理的 dep。这里有个值得多说两句的设计历史Vue3 在早期版本里使用Set.add加effect.deps.push(dep)的方式当时没有做重复收集检测依赖重复执行时可能出现 effect 被同一个 dep 收集多次的边界问题。后来引入id标记做去重也就是现在看到的dep.get(activeEffect) undefined判断。这说明依赖收集的性能敏感即便是 set 和 map 的选取、重复检测的实现都反复调优过。4.3 为什么 track 要在 get 拦截器里触发reactive 的 Proxy get 拦截器baseHandlers.ts中的createGetter在返回值之前会调用track(target, TrackOpTypes.GET, key)。也就是说响应式对象的每次属性读取都会走 track。但并非所有读取都触发依赖收集。源码里有几个判断如果是访问__v_raw、__v_isReactive这类内部 Symbol 属性会跳过。如果shouldTrack为 false比如在 effect 之外或者在停止收集的阶段直接返回。如果是for...in遍历触发的ITERATE_KEY也会走另一条分支但最终都会收敛到 trackEffects。一个常见误区是不在 effect 里读取响应式属性不会产生依赖。比如在事件回调里读state.count此时 activeEffect 为 nulltrack 直接 return不会收集任何依赖。这也是很多人调了半天发现数据变了视图没更新的根源——他们期望 Vua 能在任意位置捕获响应式依赖但实际上 Vue 的运行时依赖收集只发生在副作用执行期间。5. trigger 派发更新从属性变化到 effect 重新执行的距离5.1 trigger 主流程当属性值被修改时set 拦截器会调用trigger(target, TriggerOpTypes.SET, key)。trigger 的完整逻辑比 track 复杂一些因为它要区分数组特殊属性、集合类型、是否涉及 length 变更等。但核心主干可以浓缩为export function trigger(target, type, key) { const depsMap targetMap.get(target) if (!depsMap) { return } let deps: Dep[] [] if (type TriggerOpTypes.CLEAR) { // 集合整体清空时收集所有依赖 deps [...depsMap.values()] } else if (key ! undefined) { const dep depsMap.get(key) if (dep) deps.push(dep) } // 数组 length 特殊处理省略... const effects: ReactiveEffect[] [] for (const dep of deps) { if (dep.size) { for (const effect of dep.keys()) { // 关键因为当前正在触发的 effect 正在执行不能把它加入本轮队列 if (effect ! activeEffect) { effects.push(effect) } } } } for (const effect of effects) { triggerEffect(effect) } }这里的两个核心动作从 targetMap 中找到该响应式对象的所有相关依赖集合归拢成一个 effects 数组。逐个调用triggerEffect决定 effect 是立即重新执行还是交给 scheduler 延迟调度。5.2 triggerEffect 与 scheduler 的分岔口function triggerEffect(effect: ReactiveEffect) { if (effect.scheduler) { effect.scheduler() } else { effect.run() } }这是整个响应式系统里最重要的一个 if/else。为什么要有这个分支因为你并不总是希望副作用同步立刻执行。三个典型场景watchwatch 的回调默认是异步的数据变化后会把回调推入调度队列这靠的是scheduler里调用queuePreFlushCb实现。computedcomputed 的 effect 有lazy属性并且 trigger 只把 dirty 标记为 true真正重算要等有人 get 到它的 value 时才发生。组件渲染组件更新不会数据一变就立刻 render而是把渲染任务放入调度队列等微任务里统一 flush这保证了多次修改同一状态只触发一次渲染。反过来说如果你不做任何配置直接effect(fn)那么 fn 里的响应式依赖一变化fn 会同步执行。这种同步行为在实现简单的数据联动时很方便但在高频更新场景会造成重复执行。5.3 死循环保护为何要跳过 activeEffect在 trigger 的 effects 收集阶段有一个if (effect ! activeEffect)判断。这个判断处理的场景是副作用自己修改了自己依赖的响应式数据。举个例子effect(() { state.count })首次执行时effect 内部读取并修改了state.count。修改会触发 triggertrigger 发现依赖集合里恰好包含当前正在执行的 activeEffect 自己。如果不排除它就会陷入执行 → 修改 → 触发 → 再执行的无限循环。所以源码里明确把 activeEffect 从本轮触发队列中剔除了。这个设计叫自触发保护。这也是我在实际项目里经常遇到的死循环场景根因要么在 render 函数里改响应式状态要么在 computed getter 里推送数据流。读源码之后你才会理解Vue 不是没有能力解决这类问题而是它从设计上就不允许副作用直接修改自己的依赖这会产生无法收敛的循环。6. stop 与 cleanup防止泄漏和意外更新的防御设计6.1 cleanupEffect 做了哪些事当你调用runner.effect.stop()时实际上是调用了 ReactiveEffect 的 stop 方法。它做两步工作function cleanupEffect(effect: ReactiveEffect) { const { deps } effect if (deps.length) { for (let i 0; i deps.length; i) { deps[i].delete(effect) } deps.length 0 } }注意这里删除的是dep.delete(effect)即把 effect 从每个依赖集合中移除。而 effect.deps 数组本身也会被清空。为什么需要这一步因为如果只把effect.active设为 false依赖集合里仍然保留着这个 effect后续 trigger 仍会遍历到它并调用它的 run。虽然 run 里 activefalse 时不重新执行 fn但白白遍历一个无效 effect 既是性能浪费也增加了脏数据风险。彻底清理后trigger 就不再能看到它。6.2 stop 之后的函数调用行为stop 之后如果你手动调用runner()run 方法看到 active 为 false会直接执行 fn 并返回结果但不会重新收集依赖也不会设置 activeEffect。这是有意的行为——停止后的手动调用仍然可以运行函数本身只是它的结果不再与响应式系统挂钩。一个容易被忽略的细节stop 之后 fn 内部读取响应式属性因为 activeEffect 是 nulltrack 会直接 return所以不会重新建立依赖。这意味着即使你在停掉的 effect 里读取了 state.count这个读取也是死的之后 count 再变化不会触发它。这里还要补充一点实际使用中的建议在组件的 setup 里如果你手动创建了 effect 并需要长期存活最好关联 effectScope让组件卸载时统一 scope.stop() 清理所有副作用。依赖清理的源码机制最终目的就是避免响应式系统中出现无效节点。7. scheduler 的实战价值computed 与 watch 是怎么借用 effect 机制的7.1 computed 如何用 scheduler 实现惰性计算先看 computed 的本质计算属性的_computed内部有一个ReactiveEffect它的 fn 是计算函数scheduler 被设置为标记 dirty。用源码简化逻辑看export class ComputedRefImplT { _dirty true _value!: T constructor(getter) { this.effect new ReactiveEffect(getter, () { if (!this._dirty) { this._dirty true triggerRefValue(this) } }) } get value() { if (this._dirty) { this._dirty false this._value this.effect.run() } trackRefValue(this) return this._value } }这里 key 点是computed 的 effect 是 lazy 的不会在创建时立即执行。第一次.value时才会 run 计算逻辑设置_dirtyfalse并缓存结果。当依赖的数据变化时scheduler 被调用它只把_dirty置为 true并不会重新计算。这样设计的收益非常明显computed 只有在真正被读取时才可能重算。如果某个计算属性很昂贵但页面暂时没用它无论如何修改依赖状态它都不会执行。这跟 Vue2 的 computed 本质上是同一套思路——惰性求值加智能缓存。7.2 watch 至少两个 effect 的配合watch 的实现逻辑里核心是创建了至少一个 ReactiveEffectfn 是 getter或者包装成 getterscheduler 负责把回调推入异步队列。const effect new ReactiveEffect(getter, () { if (!initialCall) { queuePreFlushCb(() job()) } })当 getter 内部读取的响应式数据变化scheduler 触发它不会立刻跑 job 回调而是把 job 放进一个调度队列。Vue 的调度器会把这个回调包装成微任务在下一次 flush 时统一执行。这就是为什么你在 watcher 回调里拿到的 oldValue、newValue 不总是实时的——数据可能变化多次但回调只执行一次。理解了这个机制你就不会写出在 watch 回调里又修改同一响应式数据导致无限循环的代码。因为 scheduler 已经把执行延迟到队列 flush同一轮循环内多次修改状态会被去重但如果你在 watcher 回调里修改的恰恰是 getter 依赖的数据下一轮 flush 又会触发一次往复不收敛最终 console 会喷 Maximum recursive updates exceeded。7.3 组件渲染 effectvdom 更新也是 effect组件更新本质上也是 effect。Vue 的setupRenderEffect里实例的渲染函数被包在一个 effect 里scheduler 使用queueJob把组件更新推入调度队列。这一点是好些人没意识到的你写的template编译后的 render 函数其实是一个依赖了所有模板变量的副作用函数。这也是为什么 effect 源码值得认真读——读懂了它你就明白了响应式数据驱动组件更新这句话的底层实现。8. 从源码到实践调试 effect 运行时你该盯住哪些东西8.1 调试依赖收集的三种手段读源码是第一步真正动手调试会加速理解。我平时调试 effect 相关问题时常用三个手段第一利用 Vue3 提供的devtools内置调试事件。在源码中effect 的 track 和 trigger 阶段会触发onTrack和onTrigger回调这是通过全局currentInstance或debuggerEvent传递的。在开发环境下你可以通过 Vue DevTools 的响应式面板看到依赖关系的建立过程。第二在 targetMap 的 get 拦截处打断点观察每次 track 时 activeEffect 到底是谁。第三手动 wrap 一个 effect在 fn 前后打印执行堆栈。比如effect(() { console.trace(执行副作用) console.log(state.count) })这样你能直观看到首次执行与后续触发执行时的调用栈差异。8.2 实际开发中常见的 effect 相关坑在 effect 里用条件分支读取不同属性会导致依赖收集不完整。首次执行时没读到的属性之后变化不会触发 re-run。这是动态依赖的经典问题。把副作用函数塞进数组或回调后由于 this 指向变化runner 调用会失效。记得用runner.bind(effect)或用源码返回的 bound 函数。effect 内部异步读取响应式属性比如await之后读取由于 activeEffect 已经在异步前被恢复异步中的依赖不会被收集。这也是我很早就踩过的坑。在onUnmounted里不记得清理手动 effect页面组件销毁后响应式对象仍然存活在依赖集合里导致内存泄漏。现在都用 effectScope 解决。8.3 性能调优视角为什么依赖粒度越小越好Vue3 的依赖收集是属性级别的比 Vue2 组件级的收集粒度细得多。这意味着你修改一个深层嵌套对象的属性时只有依赖该属性的 effect 会重新执行同组件中依赖其他属性的 effect 完全不受影响。这是 Vue3 性能优于 Vue2 的重要支柱之一。理解了 track/trigger 的运作机制你就知道为什么 Vue3 不需要 Vue2 里那种手动优化渲染性能的 watch 模式了——它从机制上就避免了多余更新。9. 手写一个 mini effect让源码逻辑长在自己身上光看源码容易陷入看过就忘。我的建议是动手写一个 60 行左右的 mini effect把依赖收集、派发更新、stop、scheduler 都落地一遍。下面是我在理解源码过程中随手写的精简版可以直接跑起来感受效果// 简易实现targetMap 结构 const targetMap new WeakMap() let activeEffect null function track(target, key) { if (!activeEffect) return let depsMap targetMap.get(target) if (!depsMap) { targetMap.set(target, (depsMap new Map())) } let dep depsMap.get(key) if (!dep) { depsMap.set(key, (dep new Set())) } dep.add(activeEffect) activeEffect.deps.push(dep) } function trigger(target, key) { const depsMap targetMap.get(target) if (!depsMap) return const dep depsMap.get(key) if (!dep) return for (const effect of new Set(dep)) { if (effect ! activeEffect) { if (effect.scheduler) { effect.scheduler() } else { effect.run() } } } } function reactive(obj) { return new Proxy(obj, { get(target, key, receiver) { const value Reflect.get(target, key, receiver) track(target, key) return value }, set(target, key, value, receiver) { const result Reflect.set(target, key, value, receiver) trigger(target, key) return result } }) } class ReactiveEffect { constructor(fn, scheduler) { this.fn fn this.scheduler scheduler this.deps [] this.active true } run() { if (!this.active) return this.fn() const prev activeEffect activeEffect this const result this.fn() activeEffect prev return result } stop() { if (this.active) { this.deps.forEach(dep dep.delete(this)) this.deps.length 0 this.active false } } } function effect(fn, options {}) { const _effect new ReactiveEffect(fn, options.scheduler) if (!options.lazy) _effect.run() const runner _effect.run.bind(_effect) runner.effect _effect return runner }你可以用这段代码跑个例子验证const state reactive({ count: 0 }) const runner effect(() { console.log(count is:, state.count) }) // 输出: count is: 0 state.count 1 // 输出: count is: 1同步触发 runner.effect.stop() state.count 2 // 无输出已停止跑通这个 mini 版之后再回头看 Vue3 源码你会发现 90% 的命名和结构你已经能对号入座了。剩余 10% 的差异在于边界处理、批量调度、性能优化以及组件层级的整合。我个人在实际阅读中的体会是源码不需要一口气读完而是应该带着问题读。比如你在项目里遇到computed 反复重算的问题就回去翻 computed.ts遇到watch 回调不触发的困境就回来看 effect 的 scheduler 分支。每解决一个问题你对响应式系统的理解就加深一层。等你积累到某个临界点Vue3 的响应式就不再是黑盒了。

相关新闻

SQLCipher加密SQLite快速验证包testsqliteCipher.7z实战指南

SQLCipher加密SQLite快速验证包testsqliteCipher.7z实战指南

简介:本资源是面向Qt5开发者的一套SQLite数据库加密实战项目,聚焦于使用SQLCipher实现256位AES加密/解密,适用于桌面应用中敏感数据的安全存储场景,尤其适合具备C和Qt基础、正探索数据库安全增强方案的中阶开发者。压缩包为7z格式…

2026/10/9 11:42:44 阅读更多 →
AI重构前端开发:框架之争落幕,系统思维与协作能力成为新护城河

AI重构前端开发:框架之争落幕,系统思维与协作能力成为新护城河

前端圈最近有个很有意思的迹象:大家在群里讨论的不再是“React 和 Vue 哪个好”“要不要学 Next.js”,而是“AI 辅助开发怎么落地”“团队要不要引入 AI 编码工具”。说实话,“别再卷框架了”这个声音越来越多,是因为 AI 时代的前…

2026/10/9 11:42:44 阅读更多 →
会议室管理系统实战:从Excel排班到高并发预约引擎

会议室管理系统实战:从Excel排班到高并发预约引擎

简介:这份会议室管理系统资源面向高校计算机相关专业学生与课程设计实践者,围绕数据库课程设计场景,提供从需求调研、概念模型与逻辑结构设计,到数据库建表、图形化界面编程实现的完整参考方案,帮助解决会议室预约、使…

2026/10/9 11:41:42 阅读更多 →

最新新闻

小而致命:东部长鼻蝰蛇毒液的年龄变化如何影响抗蛇毒血清疗效 | MDPI Toxins

小而致命:东部长鼻蝰蛇毒液的年龄变化如何影响抗蛇毒血清疗效 | MDPI Toxins

东部长鼻蝰蛇 (Vipera ammodytes meridionalis) 被认为是欧洲最毒的蛇之一,其毒液可导致凝血功能障碍、肌损伤和神经毒性。然而,幼蛇与成蛇之间的毒液差异是否会影响临床治疗,此前从未被系统研究过。 澳大利亚昆士兰大学Bryan G. Fry教授团队…

2026/10/9 12:13:22 阅读更多 →
安全加速(进阶篇)最佳实践与踩坑记录

安全加速(进阶篇)最佳实践与踩坑记录

本文深入探讨安全加速(进阶篇),涵盖背景分析、原理剖析、实战步骤、配置示例、优化建议和避坑指南。很多团队在跨境电商与场景中都会遇到与安全加速(进阶篇)相关的挑战。本文结合生产环境经验,给出从诊断到…

2026/10/9 12:13:22 阅读更多 →
一文读懂Saga分布式事务方案(进阶篇)

一文读懂Saga分布式事务方案(进阶篇)

本文深入探讨Saga分布式事务方案(进阶篇),涵盖背景分析、原理剖析、实战步骤、配置示例、优化建议和避坑指南。很多团队在系统架构设计场景中都会遇到与Saga分布式事务方案(进阶篇)相关的挑战。本文结合生产环境经验&a…

2026/10/9 12:13:22 阅读更多 →
排队1534位后,我用华为云码道AI做出了月圆家国中秋国企文化展

排队1534位后,我用华为云码道AI做出了月圆家国中秋国企文化展

排队1534位后,我用华为云码道AI做出了月圆家国中秋国企文化展海上生明月,天涯共此时。一、项目背景 中秋节是中华民族最重要的传统节日之一,承载着团圆、思念、感恩的文化内涵。而在万家团圆的背后,是无数国企人坚守岗位、守护万家…

2026/10/9 12:13:21 阅读更多 →
构建智能体的专业技能树:Agent Skills生态全析(中篇)——从零搭建可复用的技能注册与调度层

构建智能体的专业技能树:Agent Skills生态全析(中篇)——从零搭建可复用的技能注册与调度层

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 12:13:21 阅读更多 →
CMake UseSWIG 模块完全指南:用 swig_add_library 将 C/C++ 封装为 Python、Java、C 等语言扩展

CMake UseSWIG 模块完全指南:用 swig_add_library 将 C/C++ 封装为 Python、Java、C 等语言扩展

构建工具开发工具CLI 【免费下载链接】CMake Mirror of CMake upstream repository 项目地址: https://gitcode.com/gh_mirrors/cm/CMake 点击查看 免费下载 UseSWIG 是 CMake 官方模块,用于在构建系统中集成 SWIG 中的底层实现原理(自定义命…

2026/10/9 12:12:20 阅读更多 →

日新闻

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API这个话题,隔三差五就会在群里被翻出来讨论一次。上周还有个同事线上处理一个订单超时问题,排查到最后发现是ZonedDateTime序列化后时区丢了,用户在下单当天晚上看到的时间整整差了8个小时。这类问题几乎每个做Java开发的人都遇到过…

2026/10/9 0:00:49 阅读更多 →
EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

前几个月我手头有好几台机器需要互相访问:办公室台式机、家里 NAS、还有一台云主机。如果只是偶尔传个文件倒还好,问题是工作场景经常要在几处环境之间来回切换,每次都先登录跳板机再层层代理,实在折腾。我先后试过端口映射、自建…

2026/10/9 0:00:49 阅读更多 →
AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent 这个词在过去一年里被反复提及,但真正动手搭过一套能跑起来的 Agent 系统的人都知道,从"知道它是什么"到"让它稳定干活"之间隔着一整套工程决策。我前后参与过几个 Agent 项目的落地,从最初用现成框架拼装&…

2026/10/9 0:01:50 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:40 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 10:11:06 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 21:13:17 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 6:17:20 阅读更多 →