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

【Vue3源码解析】响应式原理

源码环境搭建

【Vue3源码解析】应用实例创建及页面渲染-CSDN博客

写文章时的Vue 版本:

"version": "3.5.13",

针对单个包进行开发环境打包、测试。

pnpm run dev reactivity

image-20250215180341644

image-20250215180401097

reactive 创建响应式对象

packages/reactivity/src/reactive.ts

export function reactive(target: object) {// if trying to observe a readonly proxy, return the readonly version.if (isReadonly(target)) {return target}/*** 通过调用 createReactiveObject 函数,创建一个响应式对象,并返回该对象。* 第一个参数是 目标对象* 第二个参数用来判断该对象是否是只读的* mutableHandlers 是一个对象,包含了响应式对象的一些操作方法,如get、set等。* mutableCollectionHandlers 是一个对象,包含了响应式集合对象的一些操作方法,如get、set等。* reactiveMap 是一个全局 WeakMap 对象,用于缓存 target 到 响应式对象的映射关系。*/return createReactiveObject(target,false,mutableHandlers,mutableCollectionHandlers,reactiveMap,)
}
function createReactiveObject(target: Target,isReadonly: boolean,baseHandlers: ProxyHandler<any>,collectionHandlers: ProxyHandler<any>,proxyMap: WeakMap<Target, any>,
) {if (!isObject(target)) {if (__DEV__) {warn(`value cannot be made ${isReadonly ? 'readonly' : 'reactive'}: ${String(target,)}`,)}return target}// target is already a Proxy, return it.// exception: calling readonly() on a reactive object// 如果已经是 Proxy 代理对象,则直接返回if (target[ReactiveFlags.RAW] &&!(isReadonly && target[ReactiveFlags.IS_REACTIVE])) {return target}// target already has corresponding Proxy// 如果 ProxyMap 中有 target 对应的 proxy 对象 则直接返回const existingProxy = proxyMap.get(target)if (existingProxy) {return existingProxy}// only specific value types can be observed.// 类型无效 则直接返回 targetconst targetType = getTargetType(target)if (targetType === TargetType.INVALID) {return target}// 创建 target 对应的 Proxy 代理对象 并传入 baseHandlersconst proxy = new Proxy(target,// COLLECTION => Map/Set/WeakMap/WeakSettargetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers,)proxyMap.set(target, proxy)return proxy
}

effect 和它的函数参数fn的作用

packages/reactivity/src/effect.ts

/*** 创建一个响应式副作用函数** 此函数用于追踪函数内的响应式数据访问和修改,以便在数据变化时自动重新执行该函数* 它是响应式系统的核心部分,使得开发者可以轻松创建响应式的应用程序** @param fn 要追踪的副作用函数,它会接收一个用于触发副作用的函数作为参数* @param options 可选的副作用选项,允许开发者自定义副作用的行为,例如是否应该停止追踪等* @returns 返回一个绑定了副作用函数的runner函数,用于手动触发副作用*/
export function effect<T = any>(fn: () => T,// 可以由用户自定义,用于定义副作用effect的行为,例如shouldTrack、onTrack、onTrigger等// 这样可以覆盖ReactiveEffect的默认scheduler而执行自己的scheduleroptions?: ReactiveEffectOptions,
): ReactiveEffectRunner<T> {// 检查传入的函数是否已经是一个ReactiveEffect的副作用函数,如果是,则使用其内部的副作用函数if ((fn as ReactiveEffectRunner).effect instanceof ReactiveEffect) {fn = (fn as ReactiveEffectRunner).effect.fn}// 调用一次effect函数,根据传入的fn创建一个新的ReactiveEffect实例对象:_effect// 一个fn 对应一个 _effect对象// fn 同时成为_effect 对象的fn属性(形成闭包)/*** effect(fn)* fn.effect => ReactiveEffect对象* ReactiveEffect对象.fn => fn*/// 创建一个新的ReactiveEffect实例/*** 当内部执行scheduler的时候,它会回头调用effect的run,·而run方法内部会调用fn* 意味着:scheduler()=>run()=>fn()* 如何执行:那么之后我们如果想要重新执行fn函数,·只需要执行scheduler就可以了*/const e = new ReactiveEffect(fn)// 如果提供了用户自定义的配置,则将配置合并到副作用实例中if (options) {extend(e, options)}// 尝试运行副作用函数,如果在执行过程中抛出错误,则停止追踪并重新抛出错误try {e.run()} catch (err) {e.stop()throw err}// 创建并返回一个副作用函数的runner,它绑定了当前的副作用实例const runner = e.run.bind(e) as ReactiveEffectRunnerrunner.effect = e// 返回副作用函数的runner,允许手动触发副作用 e.run()=> fn()return runner
}
/*** 执行当前的副作用函数** 此函数负责执行副作用操作,并在执行前后处理一些清理和准备依赖项的工作* 它还管理副作用的执行状态,确保在执行过程中不会被中断,并在完成后清理依赖项** @returns 返回副作用函数的执行结果*/
run(): T {// TODO cleanupEffect// 检查副作用是否处于非激活状态,如果是,则直接执行副作用函数if (!(this.flags & EffectFlags.ACTIVE)) {// stopped during cleanupreturn this.fn()}// 设置当前副作用为正在运行状态this.flags |= EffectFlags.RUNNING// 执行清理上一次执行的副作用cleanupEffect(this)// 准备依赖项收集prepareDeps(this)// 保存当前正在执行的副作用和是否应该跟踪的全局状态const prevEffect = activeSubconst prevShouldTrack = shouldTrack// 设置当前执行的副作用和全局跟踪状态activeSub = thisshouldTrack = truetry {// 执行副作用函数return this.fn()} finally {// 在开发环境下,确保当前执行的副作用被正确恢复if (__DEV__ && activeSub !== this) {warn('Active effect was not restored correctly - ' +'this is likely a Vue internal bug.',)}// 清理当前执行的副作用的依赖项cleanupDeps(this)// 恢复之前保存的正在执行的副作用和是否应该跟踪的全局状态activeSub = prevEffectshouldTrack = prevShouldTrack// 清除当前副作用的正在运行状态this.flags &= ~EffectFlags.RUNNING}
}

执行fn后响应式变量依赖的收集和触发

Vue3.4 版本之前最后的一层,也就是 nameDepMap 这一层是 Set 结构,但是从 3.4 版本开始,变成了 Map ,用来记录 track 的 id,然而Vue3.5对该部分又进行了重构,不再记录id,只能说学的速度永远跟不上技术更新的速度~

image-20250215181003656

packages/reactivity/src/baseHandlers.ts

/*** BaseReactiveHandler 类实现了 ProxyHandler 接口,用于处理响应式对象的代理操作。* 它主要负责拦截和处理对响应式对象的访问和操作,根据是否只读和是否浅层次来决定如何处理这些操作。** @param _isReadonly 是否只读,如果为 true,则该响应式对象不可被修改。* @param _isShallow 是否浅层次,如果为 true,则仅对外层属性进行响应式处理,不递归处理内部属性。*/
class BaseReactiveHandler implements ProxyHandler<Target> {constructor(protected readonly _isReadonly = false,protected readonly _isShallow = false,) {}/*** 拦截对目标对象属性的获取操作。* 此方法负责处理各种情况下的属性获取,包括处理特殊的 ReactiveFlags、数组的特殊情况、* 属性的追踪、以及返回值的处理等。** @param target 目标对象,即被代理的响应式对象。* @param key 要访问的属性名。* @param receiver 代理对象或继承链上的其他对象。* @returns 属性值或处理后的值。*/get(target: Target, key: string | symbol, receiver: object): any {// 处理特殊的 ReactiveFlags 属性if (key === ReactiveFlags.SKIP) return target[ReactiveFlags.SKIP]const isReadonly = this._isReadonly,isShallow = this._isShallow// 根据不同的 ReactiveFlags 返回相应的值if (key === ReactiveFlags.IS_REACTIVE) {return !isReadonly} else if (key === ReactiveFlags.IS_READONLY) {return isReadonly} else if (key === ReactiveFlags.IS_SHALLOW) {return isShallow} else if (key === ReactiveFlags.RAW) {if (receiver ===(isReadonly? isShallow? shallowReadonlyMap: readonlyMap: isShallow? shallowReactiveMap: reactiveMap).get(target) ||// receiver is not the reactive proxy, but has the same prototype// this means the receiver is a user proxy of the reactive proxyObject.getPrototypeOf(target) === Object.getPrototypeOf(receiver)) {return target}// early return undefinedreturn}const targetIsArray = isArray(target)// 处理非只读情况下的特殊属性和方法if (!isReadonly) {let fn: Function | undefinedif (targetIsArray && (fn = arrayInstrumentations[key])) {return fn}if (key === 'hasOwnProperty') {return hasOwnProperty}}// 获取属性值,考虑内置符号和非跟踪键的情况const res = Reflect.get(target,key,// if this is a proxy wrapping a ref, return methods using the raw ref// as receiver so that we don't have to call `toRaw` on the ref in all// its class methodsisRef(target) ? target : receiver,)if (isSymbol(key) ? builtInSymbols.has(key) : isNonTrackableKeys(key)) {return res}// 在非只读情况下,跟踪属性的访问if (!isReadonly) {// 依赖追踪track(target, TrackOpTypes.GET, key)}// 根据是否浅层次和返回值的类型,决定是否需要进一步处理返回值if (isShallow) {return res}if (isRef(res)) {// ref unwrapping - skip unwrap for Array + integer key.return targetIsArray && isIntegerKey(key) ? res : res.value}if (isObject(res)) {// Convert returned value into a proxy as well. we do the isObject check// here to avoid invalid value warning. Also need to lazy access readonly// and reactive here to avoid circular dependency.return isReadonly ? readonly(res) : reactive(res)}return res}
}
class MutableReactiveHandler extends BaseReactiveHandler {constructor(isShallow = false) {super(false, isShallow)}/*** 设置一个响应式对象的属性。** 该方法重写了 `Proxy` 对象的默认 `set` 行为,实现了自定义的属性设置逻辑。* 它处理了各种情况,例如浅层响应式、只读属性和 ref 解包,以确保响应式系统的正确行为。** @param target - 被代理的原始对象。* @param key - 要设置的属性的名称或符号。* @param value - 属性的新值。* @param receiver - 代理对象本身。* @returns 返回设置属性的结果。*/set(target: Record<string | symbol, unknown>,key: string | symbol,value: unknown,receiver: object,): boolean {let oldValue = target[key]// 如果不是浅层响应式模式,需要进一步处理属性和值。if (!this._isShallow) {const isOldValueReadonly = isReadonly(oldValue)// 如果新旧值都不是浅层或只读的,将它们转换为原始状态。if (!isShallow(value) && !isReadonly(value)) {oldValue = toRaw(oldValue)value = toRaw(value)}// 如果目标不是数组且旧值是 ref 而新值不是 ref,需要特殊处理。if (!isArray(target) && isRef(oldValue) && !isRef(value)) {// 如果旧值是只读的,属性不能被设置。if (isOldValueReadonly) {return false} else {// 否则,直接设置旧值 ref 的值。oldValue.value = valuereturn true}}} else {// 在浅层模式下,对象按原样设置,无论是否是响应式的。}// 确定键是否已经存在。const hadKey =isArray(target) && isIntegerKey(key)? Number(key) < target.length: hasOwn(target, key)// 使用 Reflect.set 尝试设置属性。const result = Reflect.set(target,key,value,isRef(target) ? target : receiver,)// 如果目标是原始对象本身,根据属性是新增还是更新触发相应的副作用。if (target === toRaw(receiver)) {if (!hadKey) {// 触发新增属性的副作用。trigger(target, TriggerOpTypes.ADD, key, value)} else if (hasChanged(value, oldValue)) {// 触发更新属性的副作用。trigger(target, TriggerOpTypes.SET, key, value, oldValue)}}return result
}deleteProperty(target: Record<string | symbol, unknown>,key: string | symbol,): boolean {const hadKey = hasOwn(target, key)const oldValue = target[key]const result = Reflect.deleteProperty(target, key)if (result && hadKey) {trigger(target, TriggerOpTypes.DELETE, key, undefined, oldValue)}return result}has(target: Record<string | symbol, unknown>, key: string | symbol): boolean {const result = Reflect.has(target, key)if (!isSymbol(key) || !builtInSymbols.has(key)) {track(target, TrackOpTypes.HAS, key)}return result}ownKeys(target: Record<string | symbol, unknown>): (string | symbol)[] {track(target,TrackOpTypes.ITERATE,isArray(target) ? 'length' : ITERATE_KEY,)return Reflect.ownKeys(target)}
}

packages/reactivity/src/dep.ts

/*** 跟踪对响应式属性的访问。** 该函数会检查当前正在运行的效果(effect),并将其记录为依赖项(dep),* 这些依赖项记录了所有依赖于该响应式属性的效果。** @param target - 包含响应式属性的对象。* @param type - 定义对响应式属性的访问类型。* @param key - 要跟踪的响应式属性的标识符。*/
export function track(target: object, type: TrackOpTypes, key: unknown): void {// 仅在启用了跟踪且存在活动效果时进行跟踪。activeSub在3.4版本及之前为activeEffectif (shouldTrack && activeSub) {// 获取目标对象的依赖映射,如果不存在则创建一个新的映射。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 Dep()))dep.map = depsMapdep.key = key}// 在开发模式下记录依赖项,并包含详细信息。if (__DEV__) {dep.track({target,type,key,})} else {dep.track()}}
}
/*** 查找与目标对象(或特定属性)关联的所有依赖项,并触发存储在其中的效果。** @param target - 响应式对象。* @param type - 定义需要触发效果的操作类型。* @param key - 可用于指定目标对象中的特定响应式属性。* @param newValue - 新值,用于某些操作类型(如 SET)。* @param oldValue - 旧值,用于某些操作类型(如 SET)。* @param oldTarget - 旧的目标对象,用于某些操作类型(如 CLEAR)。*/
export function trigger(target: object,type: TriggerOpTypes,key?: unknown,newValue?: unknown,oldValue?: unknown,oldTarget?: Map<unknown, unknown> | Set<unknown>,
): void {const depsMap = targetMap.get(target)if (!depsMap) {// 从未被追踪过globalVersion++return}const run = (dep: Dep | undefined) => {if (dep) {if (__DEV__) {dep.trigger({target,type,key,newValue,oldValue,oldTarget,})} else {dep.trigger()}}}startBatch()if (type === TriggerOpTypes.CLEAR) {// 集合被清除// 触发目标对象的所有效果depsMap.forEach(run)} else {const targetIsArray = isArray(target)const isArrayIndex = targetIsArray && isIntegerKey(key)if (targetIsArray && key === 'length') {const newLength = Number(newValue)depsMap.forEach((dep, key) => {if (key === 'length' ||key === ARRAY_ITERATE_KEY ||(!isSymbol(key) && key >= newLength)) {run(dep)}})} else {// 调度 SET | ADD | DELETE 的运行if (key !== void 0 || depsMap.has(void 0)) {run(depsMap.get(key))}// 调度 ARRAY_ITERATE 对于任何数字键的变化(长度已在上方处理)if (isArrayIndex) {run(depsMap.get(ARRAY_ITERATE_KEY))}// 也对 ADD | DELETE | Map.SET 运行迭代键switch (type) {case TriggerOpTypes.ADD:if (!targetIsArray) {run(depsMap.get(ITERATE_KEY))if (isMap(target)) {run(depsMap.get(MAP_KEY_ITERATE_KEY))}} else if (isArrayIndex) {// 新索引添加到数组 -> 长度变化run(depsMap.get('length'))}breakcase TriggerOpTypes.DELETE:if (!targetIsArray) {run(depsMap.get(ITERATE_KEY))if (isMap(target)) {run(depsMap.get(MAP_KEY_ITERATE_KEY))}}breakcase TriggerOpTypes.SET:if (isMap(target)) {run(depsMap.get(ITERATE_KEY))}break}}}endBatch()
}
ITERATE_KEY))}} else if (isArrayIndex) {// 新索引添加到数组 -> 长度变化run(depsMap.get('length'))}breakcase TriggerOpTypes.DELETE:if (!targetIsArray) {run(depsMap.get(ITERATE_KEY))if (isMap(target)) {run(depsMap.get(MAP_KEY_ITERATE_KEY))}}breakcase TriggerOpTypes.SET:if (isMap(target)) {run(depsMap.get(ITERATE_KEY))}break}}}endBatch()
}

相关文章:

【Vue3源码解析】响应式原理

源码环境搭建 【Vue3源码解析】应用实例创建及页面渲染-CSDN博客 写文章时的Vue 版本&#xff1a; "version": "3.5.13",针对单个包进行开发环境打包、测试。 pnpm run dev reactivityreactive 创建响应式对象 packages/reactivity/src/reactive.ts …...

servlet中的ServletContext

设置、获取ServletContext配置信息 与ServletConfig不同的是&#xff0c;所有Servlet共享一份ServletContext 在web.xml中设置配置信息 <?xml version"1.0" encoding"UTF-8"?> <web-app xmlns"https://jakarta.ee/xml/ns/jakartaee"x…...

第1825天 | 我的创作纪念日:缘起、成长经历、大方向

目录 缘起一、成为创作者的初心&#xff08;一&#xff09;好记性不如烂笔头&#xff08;二&#xff09;文档可以帮助多个人解决同一个问题&#xff08;三&#xff09;加深自己对问题的理解&#xff0c;对技术的研究 二、实战项目中的经验分享&#xff08;一&#xff09;项目背…...

如何在 Mac 上解决 Qt Creator 安装后应用程序无法找到的问题

在安装Qt时&#xff0c;遇到了一些问题&#xff0c;尤其是在Mac上安装Qt后&#xff0c;发现Qt Creator没有出现在应用程序中。通过一些搜索和操作&#xff0c;最终解决了问题。以下是详细的记录和解决方法。 1. 安装Qt后未显示Qt Creator 安装完成Qt后&#xff0c;启动应用程…...

Java 设计模式之迭代器模式

文章目录 Java 设计模式之迭代器模式概述UML代码实现Java的迭代器 Java 设计模式之迭代器模式 概述 迭代器模式(Iterator)&#xff0c;提供一种方法顺序访问一个聚合对象中的各个元素&#xff0c;而又不暴露该对象的内部表示。 UML Iterator&#xff1a;迭代器接口&#xff…...

登录演示和功能拆解

登录演示和功能拆解 表单基础校验实现 1. 基础双向绑定 <template><el-form><el-form-item label"账号"><el-input v-model"formData.username" /></el-form-item><el-form-item label"密码"><el-inpu…...

DeepSeek深度求索API多线程批量写原创文章软件-ai痕迹极低

DeepSeek是一款由国内人工智能公司研发的大型语言模型&#xff0c;拥有强大的自然语言处理能力&#xff0c;能够理解并回答问题&#xff0c;还能辅助写代码、整理资料和解决复杂的数学问题。 与OpenAI开发的ChatGPT相比&#xff0c;DeepSeek不仅率先实现了媲美OpenAI-o1模型的…...

Redis进阶使用

在日常工作中&#xff0c;使用Redis有什么需要注意的&#xff1f; 设置合适的过期时间。尽量避免大key问题&#xff0c;避免用字符串存储过大的数据&#xff1b;避免集合的数据量太大&#xff0c;要定期清除。 常用的数据结构有哪些&#xff1f;用在什么地方&#xff1f; 按…...

Python常见面试题的详解6

1. 按字典 value 值排序 要点&#xff1a;对于给定字典&#xff0c;使用 sorted() 函数结合 items() 方法&#xff0c;依据 value 进行排序&#xff0c;也可以定义一个通用函数&#xff0c;支持按 value 升序或降序排序。示例&#xff1a; python d {a: 1, b: 2, c: 3, d: …...

Linux基础之文件权限的八进制表示法

1. Linux 文件权限概述 在 Linux 中&#xff0c;每个文件或目录都有三种基本权限&#xff0c;分别是&#xff1a; 读权限 - r&#xff1a;允许查看文件内容。写权限 - w&#xff1a;允许修改文件内容。执行权限 - x&#xff1a;允许执行文件或进入目录。 每个文件或目录的权…...

数据结构与算法面试专题——堆排序

完全二叉树 完全二叉树中如果每棵子树的最大值都在顶部就是大根堆 完全二叉树中如果每棵子树的最小值都在顶部就是小根堆 设计目标&#xff1a;完全二叉树的设计目标是高效地利用存储空间&#xff0c;同时便于进行层次遍历和数组存储。它的结构使得每个节点的子节点都可以通过简…...

《On Java进阶卷》阅读笔记(五)

第7章 IO系统 I/O流&#xff1a; IO有很多不同的来源和去处&#xff0c;如文件、控制台网络连接等&#xff0c;而且还涉及需求以很多种方式&#xff0c;如顺序读取、随机访问、缓冲、字符、按行读取、按字读取等。 Java8的函数式流相关的类和IO流之间并无关联。 IO流隐藏了…...

《代码随想录》刷题笔记——回溯篇【java实现】

文章目录 组合组合总和 III电话号码的字母组合组合总和组合总和II思路代码实现 分割回文串※思路字符串分割回文串判断效率优化※ 复原 IP 地址优化版本 子集子集 II使用usedArr辅助去重不使用usedArr辅助去重 递增子序列※全排列全排列 II重新安排行程题意代码 N 皇后解数独直…...

数值积分:通过复合梯形法计算

在物理学和工程学中&#xff0c;很多问题都可以通过数值积分来求解&#xff0c;特别是当我们无法得到解析解时。数值积分是通过计算积分区间内离散点的函数值来近似积分的结果。在这篇博客中&#xff0c;我将讨论如何使用 复合梯形法 来进行数值积分&#xff0c;并以一个简单的…...

AcWing——3624. 三值字符串

双指针解法 #include<iostream> #include<unordered_map> using namespace std; int main() {int n; cin >> n;while(n--){unordered_map<char, int> tree;string s; cin >> s;int ans 0x7fffffff; for(int i 0, j 0; j < (int)s.size();…...

【JavaEE进阶】验证码案例

目 &#x1f332;实现说明 &#x1f384;Hutool介绍 &#x1f333;准备工作 &#x1f334;约定前后端交互接口 &#x1f6a9;接口定义 &#x1f6a9;实现服务器后端代码 &#x1f6a9;前端代码 &#x1f6a9;整体测试 &#x1f332;实现说明 随着安全性的要求越来越⾼…...

Uniapp 短视频去水印解析工具开发实现

最近搞了一个有意思的小工具——短视频去水印解析器&#xff01;这玩意儿可以把短视频中的水印给抹掉&#xff0c;还能提取视频、封面等资源。整个项目用了 Uniapp 开发&#xff0c;做完后体验了一下&#xff0c;发现还挺顺手。今天就来跟大家聊聊实现思路和代码细节~ 需求分析…...

计算机网络-八股-学习摘要

一&#xff1a;HTTP的基本概念 全称&#xff1a; 超文本传输协议 从三个方面介绍HTTP协议 1&#xff0c;超文本&#xff1a;我们先来理解「文本」&#xff0c;在互联网早期的时候只是简单的字符文字&#xff0c;但现在「文本」的涵义已经可以扩展为图片、视频、压缩包等&am…...

编程速递-庆祝Delphi诞生30周年!

庆祝Delphi 30周年纪念是一个特别的时刻。 回到1995年&#xff0c;也就是30年前&#xff0c;在微软Windows和互联网时代的曙光初现之时&#xff0c;Borland Delphi的创建者们无法想象&#xff0c;当时使用Borland Delphi构建的应用程序至今仍在运行——为全世界数十亿人服务。…...

每天五分钟深度学习框架pytorch:搭建谷歌的Inception网络模块

本文重点 前面我们学习了VGG,从现在开始我们将学习谷歌公司推出的GoogLeNet。当年ImageNet竞赛的第二名是VGG,而第一名就是GoogLeNet,它的模型设计拥有很多的技巧,这个model证明了一件事:用更多的卷积,更深的层次可以得到更好的结构 GoogLeNet的网络结构 如图所示就是Go…...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

椭圆曲线密码学(ECC)

一、ECC算法概述 椭圆曲线密码学&#xff08;Elliptic Curve Cryptography&#xff09;是基于椭圆曲线数学理论的公钥密码系统&#xff0c;由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA&#xff0c;ECC在相同安全强度下密钥更短&#xff08;256位ECC ≈ 3072位RSA…...

Python爬虫实战:研究feedparser库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文&#xff1f; 多租户隔离&#xff1a;自动为接入设备追加租户前缀&#xff0c;后端按 ClientID 拆分队列。零代码鉴权&#xff1a;将入站用户名替换为 OAuth Access-Token&#xff0c;后端 Broker 统一校验。灰度发布&#xff1a;根据 IP/地理位写…...

OkHttp 中实现断点续传 demo

在 OkHttp 中实现断点续传主要通过以下步骤完成&#xff0c;核心是利用 HTTP 协议的 Range 请求头指定下载范围&#xff1a; 实现原理 Range 请求头&#xff1a;向服务器请求文件的特定字节范围&#xff08;如 Range: bytes1024-&#xff09; 本地文件记录&#xff1a;保存已…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)

🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

Rust 异步编程

Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

让AI看见世界:MCP协议与服务器的工作原理

让AI看见世界&#xff1a;MCP协议与服务器的工作原理 MCP&#xff08;Model Context Protocol&#xff09;是一种创新的通信协议&#xff0c;旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天&#xff0c;MCP正成为连接AI与现实世界的重要桥梁。…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

虚拟电厂发展三大趋势:市场化、技术主导、车网互联

市场化&#xff1a;从政策驱动到多元盈利 政策全面赋能 2025年4月&#xff0c;国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》&#xff0c;首次明确虚拟电厂为“独立市场主体”&#xff0c;提出硬性目标&#xff1a;2027年全国调节能力≥2000万千瓦&#xff0…...