useEffect onCleanup 清理异步副作用:竞态条件与 AbortController 实战

说实话,第一眼看到“使用 onCleanup 处理异步副作用”这个标题,我脑子里立刻蹦出了去年在某项目里排查过的一个线上问题:用户快速切换筛选条件,列表数据偶尔会“跳”回上一次的状态,刷新页面又恢复正常。当时我和 A 同学查了大半天,最后定位到根因就是 useEffect 里的异步请求没有正确处理清理逻辑。那是我第一次意识到,onCleanup(也就是 useEffect 返回的那个清理函数)不只是“卸载组件时做点收尾”这么简单,它是前端异步世界秩序感的来源。

这篇文章我想把这些经验完整地梳理一遍。内容会覆盖:onCleanup 的底层执行机制、六种高频异步副作用的清理写法、竞态条件的完整成因与解法、用 AbortController 真正取消网络请求,以及我在实践中反复踩过的坑。适合刚接触 React Hooks 不久、对 useEffect 清理逻辑一知半解的前端开发,也适合已经写过不少组件但偶尔被“幽灵更新”困扰的朋友。

1. 线上诡异 Bug:切个筛选条件,列表却“跳到”了旧状态

1.1 复现路径与表象

某运营后台的订单列表页,顶部有三个筛选条件:时间范围、订单状态、支付渠道。用户选择任意条件后,前端会发请求拉取新数据并渲染表格。表面上看功能一切正常,但只要用户操作够快——比如在 500 毫秒内连续切换两次“订单状态”,表格内容就有概率出现“错乱”:明明选的是“已退款”,表格里却先显示了“已支付”的数据,过一两秒才被新数据覆盖,甚至有时候直接被旧数据顶掉,一直不刷新。

这个 Bug 最恶心的地方在于:它不固定复现,只在网络环境差、接口响应慢的时候频繁出现。本地开发环境几乎看不出来,因为 localhost 的响应太快,旧请求早就返回完了。

1.2 根因:没有清理的异步副作用

把代码简化后,当时的问题长这样:

useEffect(() => { // 这里省略了参数拼接逻辑 fetchOrderList({ status, dateRange, channel }).then((data) => { // 不管请求是不是当前组件发起的,只要返回就更新状态 setOrders(data.list); }); }, [status, dateRange, channel]);

这段代码看似合理:依赖项变了就重新请求。但它漏了一个关键问题——当依赖项从 A 变成 B 时,A 对应的那个请求并没有被中断或忽略。它仍然在网络上“飞着”,等它返回时,.then回调照样执行,照样调用setOrders。

于是时间线上出现了这样的交错:

  1. 用户先选“已支付”,请求 1 发出,响应较慢。
  2. 用户紧接着改选“已退款”,请求 2 发出,响应较快。
  3. 请求 2 先返回,表格渲染“已退款”的数据,正确。
  4. 请求 1 后返回,表格被覆盖渲染成“已支付”的数据,错误。

这就是典型的异步竞态问题(Race Condition)。组件本身没有被卸载,useEffect 也没有报任何警告,但副作用的结果已经不属于当前状态了。要解决它,就得让“旧副作用”在“新副作用”开始之前被清理掉——这正是 onCleanup 的用武之地。

2. onCleanup 到底是什么:React 的“退场机制”拆解

2.1 useEffect 的返回值:不是可选项

很多人刚开始学 React Hooks 时,会下意识忽略useEffect的返回值。实际上,useEffect的第一个参数(那个函数)可以返回另一个函数,这个返回的函数就是清理函数(cleanup function),在 React 社区里也常被叫做 onCleanup。

useEffect(() => { // 副作用逻辑 return () => { // 清理逻辑 }; }, [deps]);

关键在于理解:清理函数不是只在组件卸载时才执行。它还会在每一次依赖项变化、下一次副作用重新执行之前执行。这一点极其重要。

2.2 清理函数的执行时机:卸载、依赖变化、严格模式

我把 React 官方文档和实际运行表现结合,整理出清理函数的四个执行时机:

时机场景发生的阶段
依赖项变化前[status]从"已支付"变成"已退款"新的副作用执行前,React 先调用上一次的清理函数
组件卸载时if (show) return <List />变成return null组件从页面移除前
严格模式开发环境组件初次挂载React 故意模拟“挂载→清理→再挂载”
页面隐藏或组件被缓存配合某些路由动画或缓存方案取决于具体库的实现

大多数时候我们只关注前两种,但这两种已经覆盖了 95% 的异步副作用问题。任何持续性的资源——定时器、事件监听、网络请求、WebSocket 连接——都应该能在这些时机被“回收”。

2.3 一个生活中的类比

如果把 React 组件比作一个租出去的房间,那 useEffect 就是租客入住时签的“设备使用协议”。每次依赖项变了,相当于协议到期、重新续签,React 会先让上一任租客把东西收拾好(清掉旧定时器、断开旧监听、取消旧请求),然后才让新租客入住。如果不收拾,房间里就会堆满上一任留下的垃圾——旧请求的回调就是其中最脏的那部分。

3. 六种高频异步副作用的清理姿势

3.1 定时器与延时任务

setTimeout和setInterval是最典型的“持续性副作用”。不清除的话,轻则多打一次日志,重则定时器持有组件引用导致内存泄漏。

useEffect(() => { const timer = setInterval(() => { refreshData(); }, 5000); return () => { clearInterval(timer); }; }, []);

这里有个细节:setInterval返回的 timer id 在浏览器里是数字,在 Node 环境里是对象,但clearInterval都能正确识别。清理动作必须在清理函数内部直接调用,不要在外面封装一层“可能被忘记调用”的函数。

3.2 DOM 事件与全局监听

通过addEventListener挂在window、document、body上的监听器,不会因为组件卸载而自动移除。如果不手动清理,回调会在组件销毁后继续触发,甚至多次触发。

useEffect(() => { const handleResize = () => { setViewportWidth(window.innerWidth); }; window.addEventListener("resize", handleResize); return () => { window.removeEventListener("resize", handleResize); }; }, []);

一个很容易被忽视的点是:addEventListener和removeEventListener必须传入同一个函数引用。如果在清理函数里重新写一个匿名函数,是移除不掉的。所以监听函数名要么声明在 effect 内部用常量持有,要么抽成组件外部的稳定函数。

3.3 网络请求(基础版:忽略过期响应)

如果不想上 AbortController(后面会讲),最基础的做法是用一个布尔标志位。

useEffect(() => { let cancelled = false; fetchOrderList(params).then((data) => { if (cancelled) return; setOrders(data.list); }); return () => { cancelled = true; }; }, [params]);

这段代码的核心思想是:请求本身无法撤回,但我们可以撤回“响应的处理权”。cancelled变成true之后,哪怕旧请求回来了,.then里的setOrders也不会执行。这个方案兼容所有请求库,包括自己封装的axios实例、request函数等。

3.4 订阅与连接(WebSocket、消息通道)

实时场景里的 WebSocket 连接如果不清理,切路由之后连接仍然存在,回调里再setState就会触发“对已卸载组件的状态更新”警告(React 18 里这个警告弱化了,但问题依然存在)。

useEffect(() => { const ws = new WebSocket("wss://example.com/socket"); ws.onmessage = (e) => { setLiveData(JSON.parse(e.data)); }; return () => { ws.close(); }; }, []);

类似的还有EventSource(SSE 连接)、BroadcastChannel、postMessage监听等。凡是“创建了连接/订阅了消息”的副作用,清理函数里一定要做对应的“断开/退订”操作。

3.5 动画帧与滚动计算

requestAnimationFrame在动画场景里非常常见。如果不取消,动画回调会一直循环执行,而且动画循环不会自然结束,只能通过cancelAnimationFrame主动中断。

useEffect(() => { let rafId; const loop = () => { // 计算并设置元素位置 rafId = requestAnimationFrame(loop); }; rafId = requestAnimationFrame(loop); return () => { cancelAnimationFrame(rafId); }; }, []);

3.6 异步初始化与防抖/节流

还有一种容易忽略的情况:副作用内部还有嵌套的异步逻辑。比如进入页面先拿用户配置,再用配置去初始化一个图表;或者输入框防抖搜索。

useEffect(() => { let cancelled = false; let timer; const runSearch = (keyword) => { clearTimeout(timer); timer = setTimeout(() => { if (cancelled) return; fetchSearchResult(keyword).then((data) => { if (cancelled) return; setResults(data); }); }, 300); }; runSearch(keyword); return () => { cancelled = true; clearTimeout(timer); }; }, [keyword]);

防抖里的clearTimeout和异步标志cancelled最好一起用,因为它们负责不同层次:clearTimeout阻止“尚未执行的延时回调”,cancelled阻止“已经发出但尚未返回的请求”。

4. 竞态条件:异步世界最棘手的对手

4.1 竞态是怎么产生的

竞态条件(Race Condition)指多个异步任务的执行顺序不确定,最终结果取决于哪个任务“恰好”先完成。前端最常见的竞态就是请求乱序:后发出的请求先返回,先发出的请求后返回,最终状态被旧数据覆盖。

我在第一节里说的订单列表 Bug,就是竞态的教科书案例。除了请求乱序,竞态还有两种变体:

  • 连续触发场景:搜索框每敲一个字发一次请求,第 5 次请求比第 3 次先返回,列表显示第 3 次的结果。
  • 页面切换场景:从列表页跳到详情页,列表页的请求才返回,触发已卸载组件的状态更新。

4.2 常见场景对照表

场景竞态表现清理策略
筛选条件切换旧条件数据覆盖新条件数据cancelled标志或 AbortController
搜索防抖旧关键字结果覆盖新关键字结果清理定时器 + 忽略过期响应
分页加载第 1 页数据晚返回,覆盖第 2 页请求前取消上一次请求
详情页跳转列表页请求返回后调用 setState组件卸载时中止所有请求
图片懒加载快速滚动时早期请求阻塞资源滚动节流 + 取消不可见图片请求

4.3 cancelled 标志:最朴素但有效的方案

useEffect(() => { let cancelled = false; loadData(params).then((data) => { if (cancelled) return; setData(data); }); return () => { cancelled = true; }; }, [params]);

这个方案的理解成本几乎为零,而且它适用于一切异步 API,不管底层是 fetch、axios、XMLHttpRequest 还是自己写的回调。它的局限也很明显:请求本身还在消耗网络资源,只是响应结果被忽略。如果请求很重、量很大,最好还是配合真正的请求取消机制。

4.4 为什么“请求发出去了”不等于“响应能安全落地”

从 JS 引擎的角度看,fetch 发起以后,.then回调何时执行完全由网络和事件循环决定。React 不知道也不关心这个回调是否还应该被处理。onCleanup 的核心价值,就是在 React 的“组件世界”和“外部异步世界”之间搭一座可控的桥:当组件这个“接收方”已经退出时,通知异步任务“你的结果不再需要了”。

这才是“处理异步副作用”这句话的本质——不是让异步操作不发生,而是让异步操作的结果永远不落到错误的地方。

5. 进阶:用 AbortController 真正“取消”请求

5.1 AbortController 的基本用法

AbortController是 Web 平台的标准 API,浏览器内置,专门用来“取消”基于 fetch 的网络请求。Node.js 从 15 版本左右也开始支持。

const controller = new AbortController(); fetch("/api/orders", { signal: controller.signal, }).catch((err) => { if (err.name === "AbortError") { console.log("请求被取消,忽略这个错误"); return; } throw err; }); // 取消请求 controller.abort();

注意.catch里的判断:请求被abort()后,fetch 返回的 Promise 会 reject 一个DOMException,其name属性是"AbortError"。如果不加这个判断,这个取消动作会被当成正常错误处理,可能触发全局错误上报或用户提示。

5.2 在 onCleanup 中联动:取消与标记双保险

useEffect(() => { const controller = new AbortController(); fetchOrderList(params, { signal: controller.signal }) .then((data) => { setOrders(data.list); }) .catch((err) => { if (err.name === "AbortError") return; // 其他真实错误处理 }); return () => { controller.abort(); }; }, [params]);

这一段代码基本就是我在项目里最常用的写法。controller.abort()会同时做两件事:让 fetch 的 Promise 立即 reject(.catch里被AbortError分支过滤掉),并且让浏览器真正断开网络连接,释放资源。

如果项目中用 axios,它的 CancelToken(旧版)和signal(新版)也支持类似模式。其他请求库请查阅各自的取消机制文档,思路完全一致。

5.3 结合请求封装库的注意事项

在真实项目中,请求往往被封装成统一的request函数。封装时如果忽略透传signal,onCleanup 里的controller.abort()就起不到作用。我在某公司项目里就遇到过这个坑:封装层用fetch但只透传了 url、method、data,把 signal 丢掉了,导致所有请求的取消都是“假取消”。

正确的封装姿势很简单:

export function request(url, options = {}) { return fetch(url, options).then((res) => { if (!res.ok) throw new Error(`HTTP ${res.status}`); return res.json(); }); } // 使用时 useEffect(() => { const controller = new AbortController(); request("/api/orders", { signal: controller.signal }) .then((data) => setOrders(data)) .catch((err) => { if (err.name === "AbortError") return; toast.error("加载失败"); }); return () => controller.abort(); }, [params]);

只要封装层支持透传options,调用方就能自由地往里面塞signal。

6. 实践中反复踩过的四个坑与对应解法

6.1 依赖数组漏掉关键变量

如果 effect 内部使用了某个变量,但它不在依赖数组里,清理函数和副作用都可能在“旧值”上运行。

// 错误示例 const userId = getUserId(); useEffect(() => { let cancelled = false; fetchUserInfo(userId).then(() => { if (cancelled) return; setUserInfo(data); }); return () => { cancelled = true; }; }, []); // userId 漏了

这个问题的隐蔽之处在于:userId变了,effect 不会重新执行,旧的请求可能返回并设置了错误用户的信息。排查方法很简单——打开 ESLint 的react-hooks/exhaustive-deps规则,编辑器会直接标黄。强烈建议这条规则落地到团队规范里,它救过我多次。

6.2 清理函数里的“过期闭包”

有一种写法容易踩:把清理函数单独抽出来,或者在里面访问了外部已经改变的值。

useEffect(() => { const doFetch = () => { fetch("/api/data").then((data) => { if (!cancelledRef.current) setData(data); }); }; doFetch(); return () => { // 假设这里想读取最新的 keyword console.log(keyword); // 可能拿到的是旧值 }; }, [keyword]);

React 官方文档明确说过:每个 effect 和它对应的清理函数,都在同一次渲染中生成,它们共享那一次渲染的 props 和 state。如果清理函数需要“最新”的值,应该用ref来持有可变值,而不是直接在清理函数里读取外部变量。

const keywordRef = useRef(keyword); keywordRef.current = keyword; useEffect(() => { let cancelled = false; fetchData(keywordRef.current).then((data) => { if (cancelled) return; setData(data); }); return () => { cancelled = true; console.log("清理时最新值:", keywordRef.current); }; }, [keyword]);

6.3 async 函数直接写进 useEffect

// 错误示例 useEffect(async () => { const data = await fetchData(); setData(data); }, []);

这样写的问题很明显:useEffect期待第一个参数返回“函数或 undefined”,但async函数永远返回 Promise。虽然 React 不会立刻报错,但这个 Promise 会被忽略,你根本没有地方放清理函数。同时,回调内await之后的代码不管组件是否卸载都会执行,等于完全放弃了清理能力。

正确做法是:外层普通函数,内部再声明 async 调用。

useEffect(() => { let cancelled = false; const load = async () => { const data = await fetchData(); if (cancelled) return; setData(data); }; load(); return () => { cancelled = true; }; }, []);

6.4 StrictMode 双执行让请求发两次

React 18 在开发环境下默认开启StrictMode,组件初次挂载时 effect 会执行两次:挂载 → 清理 → 再挂载。这不是 Bug,是 React 故意帮你暴露问题。如果你发现控制台里同一个请求出现了两次网络请求,原因很有可能是:

  1. 你确实写了正常的清理逻辑但没生效(检查 cleanup 是否真的执行)。
  2. 你的请求本身放在了 effect 外面(比如模块顶层、组件函数体内直接调用)。
  3. 你在依赖数组里塞了一个每次渲染都变化的对象(每次渲染都触发 effect,叠加 StrictMode 更明显)。

比如:

const params = { status, dateRange }; // 每次渲染都是新对象 useEffect(() => { fetchData(params); }, [params]); // 每次渲染依赖都不同,effect 每次都跑

解法是把依赖项拆成原始值,或者用useMemo稳定引用。这个坑在真实项目里出现频率极高,排查时先拿掉 StrictMode 试一次,如果请求次数恢复正常,那就说明 effect 的依赖设计有问题。

6.5 一个容易被忽略的“隐藏注册”

最后补一个冷门但真实的场景:某些第三方 SDK 的回调注册,不会返回值对应注销函数。比如地图 SDK 的map.on("click", handler),虽然提供了map.off("click", handler),但必须保证 handler 引用一致。组件复用时如果 handler 是内联箭头函数,每次渲染都是新引用,off移除不了旧监听。解决方式有两种:把 handler 用useCallback稳定化,或者在 effect 内部只注册一次。

const handleMapClick = useCallback((e) => { setSelectedMarker(...); }, []); useEffect(() => { map.on("click", handleMapClick); return () => { map.off("click", handleMapClick); }; }, [handleMapClick]);

7. 我现在的习惯与最后一点体会

写了这么多,总结一下我现在写 useEffect 时几乎固定的动作:先问自己这个副作用“什么时候结束”和“结束时要恢复什么”;然后无脑给 effect 配一个清理函数,哪怕暂时为空——至少把cancelled标志写好;网络请求一律挂 AbortController,.catch里永远先判断是不是AbortError;依赖数组交给 ESLint 插件自动检查,坚决不手动关闭这个规则。

再分享一个小技巧,适用于接口特别多的页面:把“请求 + 取消”封装成一个自定义 Hook,比如useFetchData,内部统一处理取消逻辑,业务组件就再也看不到AbortError的干扰了。

说实话,onCleanup 这个概念本身不难,难的是从“会写”到“记得用”。很多线上 Bug 排查到最后都是同一个问题——某个 effect 忘了清理,某个请求忘了忽略过期响应。我现在拿到任何一段 useEffect 代码,第一反应都是:它的清理函数写了吗?写对了吗?执行时机对吗?这三个问题想清楚,异步副作用带来的十之八九的问题都能提前拦住。

相关新闻

拼豆店计时计费软件怎么选?真实运营者深度体验与避坑指南

拼豆店计时计费软件怎么选?真实运营者深度体验与避坑指南

1. 拼豆店计时计费&#xff0c;为什么需要专用软件开了两年拼豆店&#xff0c;我一开始真没把这玩意儿当回事。店里就十几张桌子&#xff0c;顾客来了登记一下&#xff0c;走的时候按时间算钱&#xff0c;拿个本子记就行。但生意一忙起来&#xff0c;问题全冒出来了。拼豆这种业…

2026/10/20 23:07:30 阅读更多 →
局域网考试系统终版:零故障闭环架构与防作弊实战

局域网考试系统终版:零故障闭环架构与防作弊实战

简介&#xff1a;本资源为一款面向中小学及高校教师的局域网考试系统终版软件&#xff0c;专为封闭式电子化课堂测验与期中期末考核场景设计&#xff0c;解决传统纸质考试组卷耗时、阅卷效率低、防作弊能力弱等痛点。压缩包为RAR格式&#xff0c;大小7.58MB&#xff0c;含安装程…

2026/10/20 23:07:30 阅读更多 →
项目申报人为什么要研究售电?从政策逻辑到申报路径

项目申报人为什么要研究售电?从政策逻辑到申报路径

先回答标题里那个问题&#xff1a;一个做项目申报的人&#xff0c;为什么要研究售电&#xff1f;我的答案很简单——因为客户拿着售电项目的申报需求找上门了&#xff0c;而且不止一个。第一次接到这类咨询时&#xff0c;我心里也没底&#xff0c;毕竟售电这个领域&#xff0c;…

2026/10/20 23:07:30 阅读更多 →

最新新闻

AF_XDP 实战指南:Ubuntu 24.04 上基于 eBPF 的高性能包处理

AF_XDP 实战指南:Ubuntu 24.04 上基于 eBPF 的高性能包处理

1. 项目概述&#xff1a;AF_XDP 到底解决什么问题碰上 AF_XDP 这个技术点的人&#xff0c;多半是已经在 Linux 上做高性能包处理&#xff0c;或者被 DPDK 的运维成本折腾过之后&#xff0c;想在内核生态里找个折中方案。AF_XDP 不是一个框架&#xff0c;而是 Linux 内核提供的地…

2026/10/20 23:41:33 阅读更多 →
用Unity打造桌面精灵:透明窗口、鼠标穿透与动画实战

用Unity打造桌面精灵:透明窗口、鼠标穿透与动画实战

简介&#xff1a;这是一份基于Unity引擎开发桌面精灵的完整工程资源&#xff0c;面向希望实现类似QQ宠物透明浮动桌面形象的Unity开发者。资源围绕窗口无边界设置、透明材质渲染、UI布局、Animator动画控制以及鼠标交互事件等关键技术点组织&#xff0c;适合有一定Unity基础、想…

2026/10/20 23:41:33 阅读更多 →
GLSL变量与类型系统详解:从标量到矩阵的Shader避坑指南

GLSL变量与类型系统详解:从标量到矩阵的Shader避坑指南

如果你写过一段时间的着色器&#xff0c;大概率遇到过这种时刻&#xff1a;shader编译失败&#xff0c;错误信息指向某个变量&#xff0c;你盯着那一行看了很久&#xff0c;愣是没发现哪里有问题。我印象最深的一次是在某个延迟渲染demo里&#xff0c;片元着色器把法线数据当成…

2026/10/20 23:41:33 阅读更多 →
C语言是什么?从底层原理到上手路径的全面解析

C语言是什么?从底层原理到上手路径的全面解析

编程这行干久了&#xff0c;总会被外行朋友或刚入行的新人问到同一个问题&#xff1a;“C语言到底是什么&#xff1f;” 每次被问到&#xff0c;我都会愣一下&#xff0c;因为这个问题看似简单&#xff0c;真要一两句话说清楚还挺难。它不像Java能“写安卓APP”&#xff0c;也不…

2026/10/20 23:41:33 阅读更多 →
好写作AI如何用游戏化设计破解写作恐惧,养成写作习惯

好写作AI如何用游戏化设计破解写作恐惧,养成写作习惯

1. 好写作AI到底在做什么&#xff1a;把“写作”变成“练级”1.1 它解决了什么问题&#xff1a;写作恐惧不是懒&#xff0c;是“防御”我见过太多人说自己“不会写”“写不出来”&#xff0c;包括我自己也曾是这样。面对一个空白文档&#xff0c;光标一开一合&#xff0c;脑子里…

2026/10/20 23:41:33 阅读更多 →
华三AC WX5560H AP信道优化实战:解决信号满格却卡顿

华三AC WX5560H AP信道优化实战:解决信号满格却卡顿

前阵子在某园区处理无线投诉时&#xff0c;我碰到一个很典型的场景&#xff1a;AP 装了一堆、信号显示也是满格&#xff0c;但视频会议就是动不动卡成 PPT。当时很多人第一反应是带宽不够&#xff0c;可跑到华三 AC WX5560H 上一看&#xff0c;控制器负载很低&#xff0c;出口带…

2026/10/20 23:40:32 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

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

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

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

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

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

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/20 20:43:59 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 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/20 10:02:08 阅读更多 →
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/20 9:50: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/20 9:50:45 阅读更多 →