<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/scripts/pretty-feed-v3.xsl" type="text/xsl"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:h="http://www.w3.org/TR/html4/"><channel><title>lin</title><description>lin</description><link>https://linme.cn</link><item><title>如何判断 AI 生成的代码是可靠的？会从类型、测试、边界条件、性能、安全哪些维度检查？</title><link>https://linme.cn/blog/ai/ai%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E5%85%B6%E4%BB%96/%E5%A6%82%E4%BD%95%E5%88%A4%E6%96%AD-ai-%E7%94%9F%E6%88%90%E7%9A%84%E4%BB%A3%E7%A0%81%E6%98%AF%E5%8F%AF%E9%9D%A0%E7%9A%84%E4%BC%9A%E4%BB%8E%E7%B1%BB%E5%9E%8B%E6%B5%8B%E8%AF%95%E8%BE%B9%E7%95%8C%E6%9D%A1%E4%BB%B6%E6%80%A7%E8%83%BD%E5%AE%89%E5%85%A8%E5%93%AA%E4%BA%9B%E7%BB%B4%E5%BA%A6%E6%A3%80%E6%9F%A5</link><guid isPermaLink="true">https://linme.cn/blog/ai/ai%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E5%85%B6%E4%BB%96/%E5%A6%82%E4%BD%95%E5%88%A4%E6%96%AD-ai-%E7%94%9F%E6%88%90%E7%9A%84%E4%BB%A3%E7%A0%81%E6%98%AF%E5%8F%AF%E9%9D%A0%E7%9A%84%E4%BC%9A%E4%BB%8E%E7%B1%BB%E5%9E%8B%E6%B5%8B%E8%AF%95%E8%BE%B9%E7%95%8C%E6%9D%A1%E4%BB%B6%E6%80%A7%E8%83%BD%E5%AE%89%E5%85%A8%E5%93%AA%E4%BA%9B%E7%BB%B4%E5%BA%A6%E6%A3%80%E6%9F%A5</guid><description>判断 AI 生成的代码是否可靠：别只看“能跑”，要看“扛不扛打”</description><pubDate>Mon, 20 Apr 2026 10:23:02 GMT</pubDate><content:encoded>&lt;h1&gt;判断 AI 生成的代码是否可靠：别只看“能跑”，要看“扛不扛打”&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;一段代码的可靠性，从来不是靠“看起来挺像那么回事”来判断。&lt;br&gt;
真正有分量的标准，通常只有五个字：&lt;strong&gt;出了事没崩&lt;/strong&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;很多 AI 生成代码，第一眼都很顺眼：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;命名像样&lt;/li&gt;
&lt;li&gt;结构工整&lt;/li&gt;
&lt;li&gt;注释完整&lt;/li&gt;
&lt;li&gt;主流程还能跑通&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;问题也恰恰出在这里。&lt;br&gt;
&lt;strong&gt;“像代码”&lt;/strong&gt; 和 &lt;strong&gt;“可靠”&lt;/strong&gt;，中间隔着很远。&lt;/p&gt;
&lt;p&gt;判断时，通常会按 5 个核心维度过一遍：&lt;/p&gt;
&lt;p&gt;| 维度 | 重点看什么 | 最危险的信号 |
| --- | --- | --- |
| 类型 | 约束是否清楚 | &lt;code&gt;try?&lt;/code&gt;、强解包、魔法字符串满天飞 |
| 测试 | 是否真能防回归 | 只测 happy path |
| 边界条件 | 异常情况会不会碎 | 空数据、重复点击、失败回滚没处理 |
| 性能 | 主路径是否流畅 | 主线程重活、无意义重绘、任务不取消 |
| 安全 | 数据和权限是否守住 | 敏感日志、硬编码、输入不校验 |&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;1. 类型：代码是在表达约束，还是在逃避约束&lt;/h2&gt;
&lt;p&gt;类型系统最重要的作用，不是“让编译通过”，而是&lt;strong&gt;提前限制错误的发生方式&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;可靠的代码，通常会有这些特征：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;状态清楚，互斥场景用 &lt;code&gt;enum&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;模型明确，不靠松散字典拼数据&lt;/li&gt;
&lt;li&gt;Optional 被认真处理，不靠 &lt;code&gt;!&lt;/code&gt; 硬冲过去&lt;/li&gt;
&lt;li&gt;错误有语义，不是随手吞掉&lt;/li&gt;
&lt;li&gt;异步代码遵守线程和 actor 语义&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最该警惕的几种写法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;到处都是 &lt;code&gt;String&lt;/code&gt;、&lt;code&gt;Any&lt;/code&gt;、布尔开关&lt;/li&gt;
&lt;li&gt;&lt;code&gt;try?&lt;/code&gt; 一路吞错，失败像没发生过&lt;/li&gt;
&lt;li&gt;&lt;code&gt;if a &amp;#x26;&amp;#x26; !b &amp;#x26;&amp;#x26; c&lt;/code&gt; 这种布尔组合在驱动复杂状态&lt;/li&gt;
&lt;li&gt;UI 更新和后台任务混在一起&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一句话总结：&lt;br&gt;
&lt;strong&gt;类型越精确，运行时踩雷的概率越低。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;2. 测试：不是看跑了多少，而是看挡不挡得住回归&lt;/h2&gt;
&lt;p&gt;很多 AI 代码的问题，不是完全没有测试，而是测试只覆盖了最顺的那条路。&lt;/p&gt;
&lt;p&gt;例如这种情况就很常见：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;页面能打开&lt;/li&gt;
&lt;li&gt;按钮能点&lt;/li&gt;
&lt;li&gt;提交能成功&lt;/li&gt;
&lt;li&gt;测试一片绿色&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但下面这些没测：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;空数据&lt;/li&gt;
&lt;li&gt;重复提交&lt;/li&gt;
&lt;li&gt;网络失败&lt;/li&gt;
&lt;li&gt;本地保存失败&lt;/li&gt;
&lt;li&gt;页面切走时任务取消&lt;/li&gt;
&lt;li&gt;旧数据迁移&lt;/li&gt;
&lt;li&gt;删除后恢复&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;真正有价值的测试，通常要覆盖：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;正常路径&lt;/li&gt;
&lt;li&gt;异常路径&lt;/li&gt;
&lt;li&gt;空状态&lt;/li&gt;
&lt;li&gt;loading 状态&lt;/li&gt;
&lt;li&gt;权限变化&lt;/li&gt;
&lt;li&gt;并发触发&lt;/li&gt;
&lt;li&gt;回归场景&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;还有一个很实用的判断标准：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;测试是在验证“结果”，还是只是在验证“某个方法被调用过”？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果只断言某个函数被调过一次，这类测试通常很热闹，但防不住真实问题。&lt;/p&gt;
&lt;p&gt;可靠的测试，最好具备两个特点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;稳定&lt;/strong&gt;：不靠 &lt;code&gt;sleep&lt;/code&gt;、不靠真实网络、不靠运气&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;有针对性&lt;/strong&gt;：改了什么风险，就测什么风险&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;3. 边界条件：真正拉开差距的地方&lt;/h2&gt;
&lt;p&gt;AI 最擅长生成 happy path。&lt;br&gt;
真正决定质量下限的，往往是边界条件。&lt;/p&gt;
&lt;p&gt;一段代码是否可靠，至少要问完这些问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;输入为空怎么办&lt;/li&gt;
&lt;li&gt;字段缺失怎么办&lt;/li&gt;
&lt;li&gt;数据损坏怎么办&lt;/li&gt;
&lt;li&gt;第一次启动怎么办&lt;/li&gt;
&lt;li&gt;权限被拒绝怎么办&lt;/li&gt;
&lt;li&gt;用户连续点击怎么办&lt;/li&gt;
&lt;li&gt;任务还没结束，页面已经退出怎么办&lt;/li&gt;
&lt;li&gt;删除失败怎么办&lt;/li&gt;
&lt;li&gt;磁盘写满怎么办&lt;/li&gt;
&lt;li&gt;同步冲突怎么办&lt;/li&gt;
&lt;li&gt;应用进后台再回来怎么办&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;尤其是数据类产品，边界条件不是附属问题，而是主战场。&lt;/p&gt;
&lt;p&gt;比如日记、笔记、清单这类应用，最怕的不是界面偶尔抖一下，而是下面这些：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;误删&lt;/li&gt;
&lt;li&gt;覆盖失败&lt;/li&gt;
&lt;li&gt;自动保存丢失&lt;/li&gt;
&lt;li&gt;迁移损坏&lt;/li&gt;
&lt;li&gt;恢复不完整&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;真正可靠的代码，不是“尽量别出错”，而是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;出错时也有明确行为，失败时也能被看见。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2&gt;4. 性能：不卡，不等于性能没问题&lt;/h2&gt;
&lt;p&gt;性能问题最容易被忽略，因为很多时候功能确实“能用”。&lt;/p&gt;
&lt;p&gt;但“能用”和“顺手”中间，也隔着好几层体验差距。&lt;/p&gt;
&lt;p&gt;常见风险点通常有这些：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;主线程做 IO、解析、图片处理、排序&lt;/li&gt;
&lt;li&gt;SwiftUI 状态设计粗糙，导致整棵树反复刷新&lt;/li&gt;
&lt;li&gt;列表没有稳定 identity&lt;/li&gt;
&lt;li&gt;搜索输入不做节流&lt;/li&gt;
&lt;li&gt;异步任务到处开，不取消&lt;/li&gt;
&lt;li&gt;缓存只加不清&lt;/li&gt;
&lt;li&gt;动画过重，拖慢滚动和输入&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;性能判断，不能只看代码长什么样，还得看运行时表现：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;首屏是否慢&lt;/li&gt;
&lt;li&gt;输入是否跟手&lt;/li&gt;
&lt;li&gt;列表是否掉帧&lt;/li&gt;
&lt;li&gt;页面切换是否发闷&lt;/li&gt;
&lt;li&gt;后台任务是否空转&lt;/li&gt;
&lt;li&gt;发热和耗电是否异常&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果是 iOS UI 改动，最稳妥的证据通常是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;模拟器真实交互&lt;/li&gt;
&lt;li&gt;截图或录屏&lt;/li&gt;
&lt;li&gt;必要时加日志或 Instruments&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;5. 安全：功能完成，不代表边界安全&lt;/h2&gt;
&lt;p&gt;AI 写代码时，很容易把“跑通功能”放在第一位，然后把安全问题留在角落。&lt;/p&gt;
&lt;p&gt;最常见的坑有这些：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;敏感信息打印进日志&lt;/li&gt;
&lt;li&gt;token、路径、用户内容被硬编码或暴露&lt;/li&gt;
&lt;li&gt;导出、分享、文件访问边界不清楚&lt;/li&gt;
&lt;li&gt;外部输入不校验&lt;/li&gt;
&lt;li&gt;错误提示暴露内部实现&lt;/li&gt;
&lt;li&gt;权限申请过度，解释不足&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;尤其是内容类应用，下面这些都属于敏感数据：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;文本内容&lt;/li&gt;
&lt;li&gt;搜索词&lt;/li&gt;
&lt;li&gt;时间信息&lt;/li&gt;
&lt;li&gt;文件路径&lt;/li&gt;
&lt;li&gt;导出记录&lt;/li&gt;
&lt;li&gt;同步状态&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;真正可靠的代码，在安全上通常有两个特点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;默认保守，不默认放开&lt;/li&gt;
&lt;li&gt;出错时不泄露不该泄露的东西&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;6. 最后补一刀：结构能不能撑住下一次修改&lt;/h2&gt;
&lt;p&gt;有些 AI 代码第一次看不差，第二次改就开始崩。&lt;br&gt;
问题不一定出在功能上，而是出在结构上。&lt;/p&gt;
&lt;p&gt;典型信号包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;View 里塞业务逻辑&lt;/li&gt;
&lt;li&gt;ViewModel 里塞持久化&lt;/li&gt;
&lt;li&gt;Repository 里塞展示格式化&lt;/li&gt;
&lt;li&gt;一个文件越来越大，什么都往里加&lt;/li&gt;
&lt;li&gt;复制第三份相似逻辑，而不是抽共用部分&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可靠的代码，不只是“当前能跑”，还要满足：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;职责边界清楚&lt;/li&gt;
&lt;li&gt;后续修改不容易误伤&lt;/li&gt;
&lt;li&gt;问题出现时好定位&lt;/li&gt;
&lt;li&gt;不会因为小改动把整个模块带乱&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这部分不一定立刻炸，但一定会影响长期稳定性。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;一份简单的检查清单&lt;/h2&gt;
&lt;p&gt;看到一段 AI 生成代码时，快速扫这一遍，基本就能判断个八九不离十：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;能否完整 build，通过后是否没有新增 warning&lt;/li&gt;
&lt;li&gt;类型是否准确表达状态，而不是一堆布尔拼逻辑&lt;/li&gt;
&lt;li&gt;是否存在强解包、静默失败、魔法字符串&lt;/li&gt;
&lt;li&gt;是否补了针对本次改动的回归测试&lt;/li&gt;
&lt;li&gt;是否覆盖异常路径和空状态&lt;/li&gt;
&lt;li&gt;边界条件是否被明确处理&lt;/li&gt;
&lt;li&gt;主线程是否做了不该做的事&lt;/li&gt;
&lt;li&gt;UI 是否可能因为状态变化被过度刷新&lt;/li&gt;
&lt;li&gt;是否存在敏感日志、硬编码、输入不校验&lt;/li&gt;
&lt;li&gt;文件职责是否仍然清楚，是否新增了新的大而全类型&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;结尾&lt;/h2&gt;
&lt;p&gt;判断 AI 代码是否可靠，核心从来不是“像不像专业工程师写的”，而是下面这句话：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;类型能不能拦错，测试能不能兜底，边界会不会碎，性能会不会掉，安全会不会漏。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>tmux 使用指南</title><link>https://linme.cn/blog/%E8%AE%A1%E7%AE%97%E6%9C%BA/%E8%BD%AF%E4%BB%B6/%E7%BB%88%E7%AB%AF/tmux-%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97</link><guid isPermaLink="true">https://linme.cn/blog/%E8%AE%A1%E7%AE%97%E6%9C%BA/%E8%BD%AF%E4%BB%B6/%E7%BB%88%E7%AB%AF/tmux-%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97</guid><description>核心定位</description><pubDate>Fri, 27 Mar 2026 16:46:59 GMT</pubDate><content:encoded>&lt;h2&gt;核心定位&lt;/h2&gt;
&lt;p&gt;终端复用工具，核心解决两大痛点：&lt;strong&gt;终端关闭/SSH断开后任务不中断&lt;/strong&gt;、&lt;strong&gt;单终端内多工作区/分屏管理&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;一、核心层级概念&lt;/h2&gt;
&lt;p&gt;| 层级 | 核心说明 |
|------|----------|
| &lt;strong&gt;Session（会话）&lt;/strong&gt; | 最高级独立工作环境，对应一个完整项目/任务 |
| &lt;strong&gt;Window（窗口）&lt;/strong&gt; | 会话内的标签页，一个会话可创建多个 |
| &lt;strong&gt;Pane（面板）&lt;/strong&gt; | 窗口内的分屏区域，一个窗口可切分多个 |&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;二、安装&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Mac（Homebrew）：&lt;code&gt;brew install tmux&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Linux/WSL（Debian/Ubuntu）：&lt;code&gt;sudo apt update &amp;#x26;&amp;#x26; sudo apt install tmux&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;三、快捷键规则&lt;/h2&gt;
&lt;p&gt;所有快捷键需先按&lt;strong&gt;前缀键&lt;/strong&gt;（默认 &lt;code&gt;Ctrl+b&lt;/code&gt;），松手后再按功能键。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;推荐修改为 &lt;code&gt;Ctrl+a&lt;/code&gt;（操作更顺手），修改方法见配置章节。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2&gt;四、高频命令&amp;#x26;快捷键&lt;/h2&gt;
&lt;h3&gt;会话管理（核心）&lt;/h3&gt;
&lt;p&gt;| 操作 | 终端命令（会话外执行） | 快捷键（会话内） |
|------|------------------------|------------------|
| 新建命名会话 | &lt;code&gt;tmux new -s &amp;#x3C;会话名&gt;&lt;/code&gt; | - |
| 查看所有会话 | &lt;code&gt;tmux ls&lt;/code&gt; | &lt;code&gt;Ctrl+b s&lt;/code&gt;（可视化切换） |
| 恢复指定会话 | &lt;code&gt;tmux attach -t &amp;#x3C;会话名&gt;&lt;/code&gt; | - |
| 后台分离会话（任务保留） | - | &lt;code&gt;Ctrl+b d&lt;/code&gt; |
| 重命名当前会话 | - | &lt;code&gt;Ctrl+b $&lt;/code&gt; |
| 关闭指定会话 | &lt;code&gt;tmux kill-session -t &amp;#x3C;会话名&gt;&lt;/code&gt; | - |&lt;/p&gt;
&lt;h3&gt;窗口管理&lt;/h3&gt;
&lt;p&gt;| 操作 | 快捷键 |
|------|--------|
| 新建窗口 | &lt;code&gt;Ctrl+b c&lt;/code&gt; |
| 关闭当前窗口 | &lt;code&gt;Ctrl+b &amp;#x26;&lt;/code&gt; |
| 切换上/下一个窗口 | &lt;code&gt;Ctrl+b p&lt;/code&gt; / &lt;code&gt;Ctrl+b n&lt;/code&gt; |
| 按数字切换窗口 | &lt;code&gt;Ctrl+b &amp;#x3C;0-9&gt;&lt;/code&gt; |
| 重命名当前窗口 | &lt;code&gt;Ctrl+b ,&lt;/code&gt; |&lt;/p&gt;
&lt;h3&gt;面板（分屏）管理&lt;/h3&gt;
&lt;p&gt;| 操作 | 快捷键 |
|------|--------|
| 垂直左右分屏 | &lt;code&gt;Ctrl+b %&lt;/code&gt; |
| 水平上下分屏 | &lt;code&gt;Ctrl+b &quot;&lt;/code&gt; |
| 切换面板 | &lt;code&gt;Ctrl+b &amp;#x3C;方向键&gt;&lt;/code&gt; |
| 关闭当前面板 | &lt;code&gt;Ctrl+b x&lt;/code&gt; |
| 面板临时全屏/还原 | &lt;code&gt;Ctrl+b z&lt;/code&gt; |
| 调整面板大小 | &lt;code&gt;Ctrl+b Ctrl+&amp;#x3C;方向键&gt;&lt;/code&gt; |&lt;/p&gt;
&lt;h3&gt;复制粘贴&lt;/h3&gt;
&lt;p&gt;| 操作 | 快捷键/步骤 |
|------|-------------|
| 进入复制模式（可滚动） | &lt;code&gt;Ctrl+b [&lt;/code&gt; |
| 复制内容 | 空格开始选择，回车完成复制 |
| 粘贴内容 | &lt;code&gt;Ctrl+b ]&lt;/code&gt; |
| 退出复制模式 | &lt;code&gt;q&lt;/code&gt; |&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;五、极简必用配置&lt;/h2&gt;
&lt;p&gt;编辑配置文件 &lt;code&gt;nano ~/.tmux.conf&lt;/code&gt;，粘贴以下内容，保存后执行 &lt;code&gt;tmux source ~/.tmux.conf&lt;/code&gt; 生效。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 1. 修改前缀为 Ctrl+a（可选，保留默认则注释掉）
unbind C-b
set -g prefix C-a
bind C-a send-prefix

# 2. 必开：鼠标支持（点击切换分屏、滚轮滚动、拖动调整大小）
set -g mouse on

# 3. 窗口/面板编号从1开始（默认0，操作更顺手）
set -g base-index 1
setw -g pane-base-index 1

# 4. 256色终端支持
set -g default-terminal &quot;screen-256color&quot;

# 5. 快捷键重载配置（前缀+r 一键生效）
bind r source-file ~/.tmux.conf \; display-message &quot;配置重载成功&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;六、TPM 插件管理（极简）&lt;/h2&gt;
&lt;p&gt;TPM 是 Tmux 官方插件管理器，一键安装/更新插件。&lt;/p&gt;
&lt;h3&gt;1. 安装&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. 配置&lt;/h3&gt;
&lt;p&gt;在 &lt;code&gt;~/.tmux.conf&lt;/code&gt; &lt;strong&gt;最底部&lt;/strong&gt;添加：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# TPM 插件列表
set -g @plugin &apos;tmux-plugins/tpm&apos;
set -g @plugin &apos;tmux-plugins/tmux-sensible&apos;
# 按需添加插件，例：set -g @plugin &apos;tmux-plugins/tmux-resurrect&apos;

# TPM 初始化（必须放在文件最底部）
run &apos;~/.tmux/plugins/tpm/tpm&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. 核心快捷键&lt;/h3&gt;
&lt;p&gt;| 快捷键 | 功能 |
|--------|------|
| &lt;code&gt;Ctrl+b I&lt;/code&gt; | 安装新增的插件 |
| &lt;code&gt;Ctrl+b U&lt;/code&gt; | 更新所有插件 |
| &lt;code&gt;Ctrl+b Alt+u&lt;/code&gt; | 卸载已删除配置的插件 |&lt;/p&gt;
&lt;h3&gt;4. 高频推荐插件&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;tmux-resurrect&lt;/code&gt;：手动保存/恢复会话，重启电脑也能还原工作现场&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tmux-continuum&lt;/code&gt;：配合 resurrect 实现会话自动保存、开机恢复&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tmux-yank&lt;/code&gt;：Tmux 复制内容同步到系统剪贴板&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;七、新手极简工作流&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;新建项目会话：&lt;code&gt;tmux new -s dev&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;新建窗口/分屏：&lt;code&gt;Ctrl+b c&lt;/code&gt; 建窗口，&lt;code&gt;Ctrl+b %&lt;/code&gt;/&lt;code&gt;&quot;&lt;/code&gt; 分屏&lt;/li&gt;
&lt;li&gt;临时离开：&lt;code&gt;Ctrl+b d&lt;/code&gt; 分离会话，任务后台持续运行&lt;/li&gt;
&lt;li&gt;恢复工作：&lt;code&gt;tmux attach -t dev&lt;/code&gt; 一键还原所有工作现场&lt;/li&gt;
&lt;/ol&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>常用skill</title><link>https://linme.cn/blog/ai/ai%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/skill/%E5%B8%B8%E7%94%A8skill</link><guid isPermaLink="true">https://linme.cn/blog/ai/ai%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/skill/%E5%B8%B8%E7%94%A8skill</guid><description>核心协作与任务执行</description><pubDate>Thu, 26 Mar 2026 20:50:18 GMT</pubDate><content:encoded>&lt;h2&gt;核心协作与任务执行&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;using-superpowers：在每轮任务开始时检查并调用合适的 skill&lt;/li&gt;
&lt;li&gt;writing-plans：把多步骤任务写成清晰的实施计划&lt;/li&gt;
&lt;li&gt;executing-plans：按已有计划执行，并在关键点做检查&lt;/li&gt;
&lt;li&gt;dispatching-parallel-agents：把可并行的独立任务分发给多个 agent&lt;/li&gt;
&lt;li&gt;subagent-driven-development：在当前会话里用子 agent 协同开发&lt;/li&gt;
&lt;li&gt;verification-before-completion：宣称完成前先做验证&lt;/li&gt;
&lt;li&gt;self-improving-agent：复盘对话和执行质量，优化代理表现&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;创意与产品规划&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;brainstorming：结构化头脑风暴，用于想点子、命名、产品方向、功能取舍、创意发散与收敛&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;前端开发与工程化&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;frontend-design：做高质量前端界面设计与实现，适用于网页、落地页、仪表盘、组件、美化现有 UI&lt;/li&gt;
&lt;li&gt;vervel-react-best-practices：React / Next.js 最佳实践、性能和渲染优化&lt;/li&gt;
&lt;li&gt;test-driven-development：功能或修复先写测试再实现&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;自动化与浏览器操作&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;playwright：用真实浏览器自动化执行页面操作、截图、抓取信息、调试前端流程&lt;/li&gt;
&lt;li&gt;Agent Browser：通过结构化浏览器 CLI 导航、点击、输入、抓取页面&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;GitHub 与 CI/CD&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;github：处理 GitHub 仓库、PR、issue、review、Actions&lt;/li&gt;
&lt;li&gt;gh-fix-ci：排查并修复 GitHub Actions / PR checks 失败&lt;/li&gt;
&lt;li&gt;using-git-worktrees：为新任务创建隔离的 git worktree&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;信息处理与搜索&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;tavily-search：用 Tavily 做网页搜索和结果提取&lt;/li&gt;
&lt;li&gt;summarize：总结文本、日志、文档、会议记录&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Skill 管理与开发&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;skill-vetting：安装前审查 skill 的安全性和可信度&lt;/li&gt;
&lt;li&gt;skill-creator：创建或改进新的 skill&lt;/li&gt;
&lt;li&gt;writing-skills：编写、编辑、验证 skills&lt;/li&gt;
&lt;/ul&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>如何写一个 skill</title><link>https://linme.cn/blog/ai/ai%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/skill/%E5%A6%82%E4%BD%95%E5%86%99%E4%B8%80%E4%B8%AA-skill</link><guid isPermaLink="true">https://linme.cn/blog/ai/ai%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/skill/%E5%A6%82%E4%BD%95%E5%86%99%E4%B8%80%E4%B8%AA-skill</guid><description>Skill 是什么</description><pubDate>Fri, 20 Mar 2026 22:01:25 GMT</pubDate><content:encoded>&lt;h2&gt;Skill 是什么&lt;/h2&gt;
&lt;p&gt;skill 可以理解成一组可复用的能力说明。&lt;br&gt;
它通常包含一份主文档 &lt;code&gt;SKILL.md&lt;/code&gt;，再按需要带上脚本、参考资料和素材文件。&lt;/p&gt;
&lt;p&gt;它适合解决这几类问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;某类任务有固定流程&lt;/li&gt;
&lt;li&gt;某些操作容易出错，最好约束做法&lt;/li&gt;
&lt;li&gt;有一批上下文知识，每次重复解释太浪费&lt;/li&gt;
&lt;li&gt;需要配套脚本、模板或资源文件&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不适合做这几类东西：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一次性方案&lt;/li&gt;
&lt;li&gt;项目私有约定&lt;/li&gt;
&lt;li&gt;纯靠代码校验就能解决的问题&lt;/li&gt;
&lt;li&gt;大而空的“方法论文档”&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;一个 skill 的最小结构&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;my-skill/
├── SKILL.md
├── agents/
│   └── openai.yaml
├── scripts/
├── references/
└── assets/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;说明：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SKILL.md&lt;/code&gt; 是必须的&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agents/openai.yaml&lt;/code&gt; 建议加，方便在界面里展示&lt;/li&gt;
&lt;li&gt;&lt;code&gt;scripts/&lt;/code&gt; 放脚本&lt;/li&gt;
&lt;li&gt;&lt;code&gt;references/&lt;/code&gt; 放长文档、规范、接口说明&lt;/li&gt;
&lt;li&gt;&lt;code&gt;assets/&lt;/code&gt; 放模板、图标、字体、样例文件&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不是每个 skill 都要把这些目录建全。&lt;br&gt;
没有就不要建。&lt;/p&gt;
&lt;h2&gt;写之前先把边界定清楚&lt;/h2&gt;
&lt;p&gt;先回答四个问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;这个 skill 到底解决什么问题&lt;/li&gt;
&lt;li&gt;什么情况下应该触发它&lt;/li&gt;
&lt;li&gt;什么情况下不该触发它&lt;/li&gt;
&lt;li&gt;它需要哪些配套资源&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果这四个问题说不清，先别写正文。&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;SKILL.md&lt;/code&gt; 怎么写&lt;/h2&gt;
&lt;h3&gt;1. Frontmatter 只放必要信息&lt;/h3&gt;
&lt;p&gt;最少保留两个字段：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-md&quot;&gt;---
name: editor-studio-ui
description: Use when designing or refining editor-style content studio interfaces, including workspace layout, panels, toolbars, editing flows, and implementation details.
---
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;要求很简单：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;name&lt;/code&gt; 用小写加连字符&lt;/li&gt;
&lt;li&gt;&lt;code&gt;description&lt;/code&gt; 重点写“什么时候用”&lt;/li&gt;
&lt;li&gt;不要把完整流程塞进 &lt;code&gt;description&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;让它覆盖真实会出现的任务词、场景词、文件词&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;description&lt;/code&gt; 决定这个 skill 会不会被选中。&lt;br&gt;
这部分比正文更重要。&lt;/p&gt;
&lt;h3&gt;2. 正文别写成废话&lt;/h3&gt;
&lt;p&gt;正文建议写成下面这种结构：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-md&quot;&gt;# Editor Studio UI

## Overview

用于设计和实现编辑器工作台类界面，重点处理布局、信息层级、主操作区和侧边面板。

## Workflow

1. 先看现有产品结构，不要直接推翻。
2. 先定主区域、侧栏、工具条，再谈视觉。
3. 优先保证操作路径清楚，再补细节交互。
4. 对桌面端和移动端分别给出布局策略。

## Rules

- 不要做成通用后台面板样式
- 不要把主操作和次要信息混在一个层级
- 不要为了“高级感”牺牲可读性
- 需要保留现有设计体系时，优先沿用已有模式

## Resources

- 需要布局参考时，读取 `references/layout-patterns.md`
- 需要脚手架或检查脚本时，使用 `scripts/`
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;写正文时注意几件事：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;写动作，不写空话&lt;/li&gt;
&lt;li&gt;写判断标准，不写口号&lt;/li&gt;
&lt;li&gt;写例外情况，不写泛泛原则&lt;/li&gt;
&lt;li&gt;需要长说明就拆到 &lt;code&gt;references/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;需要重复执行的逻辑就放到 &lt;code&gt;scripts/&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;一个能直接参考的 &lt;code&gt;SKILL.md&lt;/code&gt; 示例&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-md&quot;&gt;---
name: editor-studio-ui
description: Use when designing or refining editor-style content studio interfaces, including workspace layout, panels, toolbars, editing flows, and production-ready frontend implementation details.
---

# Editor Studio UI

## Overview

用于编辑器工作台类页面的设计与实现，覆盖布局组织、操作区划分、面板关系和交互优先级。

## Workflow

1. 先识别主任务区域。
2. 再区分主操作、辅助信息和状态反馈。
3. 先确定布局和层级，再处理视觉样式。
4. 兼顾桌面端与移动端的使用路径。

## Layout Rules

- 主编辑区必须保持视觉中心
- 侧边栏只承载辅助信息，不抢主操作
- 顶部工具栏保留高频动作
- 二级操作尽量下沉，避免界面噪音

## Implementation Notes

- 优先复用现有设计系统
- 没有明确要求时，不引入复杂状态管理
- 样式命名和组件拆分保持可维护性
- 交互动效只服务于信息层级和操作反馈

## Resources

- 需要布局范式时读取 `references/layout-patterns.md`
- 需要模板或资源时查看 `assets/`
- 需要可执行辅助逻辑时使用 `scripts/`
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;初始化一个 skill&lt;/h2&gt;
&lt;p&gt;如果当前环境带有初始化脚本，可以直接生成骨架：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;python init_skill.py editor-studio-ui --path &quot;$CODEX_HOME/skills&quot; --resources scripts,references,assets
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果没有这类脚本，也可以手动创建目录和文件。&lt;br&gt;
关键不是脚本，而是目录结构和内容质量。&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;openai.yaml&lt;/code&gt; 要不要写&lt;/h2&gt;
&lt;p&gt;如果你希望它在界面里显示得更完整，建议写。&lt;/p&gt;
&lt;p&gt;示例：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;interface:
  display_name: &quot;Editor Studio UI&quot;
  short_description: &quot;Editor workspace design and implementation&quot;
  default_prompt: &quot;Use $editor-studio-ui to design a production-ready editor workspace.&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;字段内容给人看，不要写成内部说明&lt;/li&gt;
&lt;li&gt;&lt;code&gt;default_prompt&lt;/code&gt; 最好短一点&lt;/li&gt;
&lt;li&gt;&lt;code&gt;default_prompt&lt;/code&gt; 里明确写出 &lt;code&gt;$skill-name&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;资源文件怎么分&lt;/h2&gt;
&lt;h3&gt;&lt;code&gt;scripts/&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;适合放这些东西：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;初始化脚本&lt;/li&gt;
&lt;li&gt;转换脚本&lt;/li&gt;
&lt;li&gt;校验脚本&lt;/li&gt;
&lt;li&gt;可重复执行的小工具&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;code&gt;references/&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;适合放这些东西：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;接口说明&lt;/li&gt;
&lt;li&gt;数据结构&lt;/li&gt;
&lt;li&gt;设计规范&lt;/li&gt;
&lt;li&gt;业务规则&lt;/li&gt;
&lt;li&gt;长篇流程文档&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;code&gt;assets/&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;适合放这些东西：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;模板&lt;/li&gt;
&lt;li&gt;图标&lt;/li&gt;
&lt;li&gt;字体&lt;/li&gt;
&lt;li&gt;示例文件&lt;/li&gt;
&lt;li&gt;可直接复用的素材&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;原则只有一个：&lt;br&gt;
能执行的放脚本，太长的放参考，最终产物要用的放素材。&lt;/p&gt;
&lt;h2&gt;怎么判断这个 skill 写得行不行&lt;/h2&gt;
&lt;p&gt;看三点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;别人第一次打开，能看懂它什么时候该用&lt;/li&gt;
&lt;li&gt;真碰到任务时，它能提供具体帮助&lt;/li&gt;
&lt;li&gt;不需要加载一堆无关内容&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果一个 skill 写完之后，正文大半都是“提高效率”“保持一致性”“确保质量”这种话，基本就该重写。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>热门 skills</title><link>https://linme.cn/blog/ai/ai%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/skill/%E7%83%AD%E9%97%A8-skills</link><guid isPermaLink="true">https://linme.cn/blog/ai/ai%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/skill/%E7%83%AD%E9%97%A8-skills</guid><description>skills.sh 上的热门 Skill。</description><pubDate>Fri, 20 Mar 2026 09:27:29 GMT</pubDate><content:encoded>&lt;p&gt;skills.sh 上的热门 Skill。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;前端开发&lt;/h2&gt;
&lt;p&gt;| Skill | 安装量 | 干嘛用的 |
|-------|--------|----------|
| vercel-react-best-practices | 37,600+ | React/Next.js 性能优化，57条具体规则 |
| frontend-design | 45,500+ | 让 AI 设计不那么&quot;一眼 AI&quot;，避开 Inter 字体、紫色渐变这些 cliché |
| web-design-guidelines | 28,500+ | 检查网页可访问性、语义化 HTML、焦点管理 |
| remotion-best-practices | 18,800+ | 用代码做视频的最佳实践 |
| building-native-ui | 2,700+ | Expo 移动端开发指南 |
| upgrading-expo | 2,200+ | Expo 版本升级专用 |
| better-auth-best-practices | 2,300+ | 登录认证避坑：密码加密、JWT、CSRF、OAuth |
| shadcn-ui | 15,000+ | shadcn/ui 组件库最佳实践，快速搭建美观界面 |
| tailwind-css | 12,500+ | Tailwind CSS 使用指南，实用类名组合技巧 |
| nextjs-production | 9,800+ | Next.js 生产环境部署优化，缓存、图片、路由策略 |&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;后端 &amp;#x26; 数据库&lt;/h2&gt;
&lt;p&gt;| Skill | 安装量 | 干嘛用的 |
|-------|--------|----------|
| prisma-best-practices | 8,200+ | Prisma ORM 使用技巧，查询优化、迁移管理 |
| supabase-schema | 6,500+ | Supabase 数据库设计，RLS 策略、实时订阅 |
| postgres-performance | 5,300+ | PostgreSQL 查询优化，索引、分区、连接池 |
| redis-patterns | 4,800+ | Redis 常见使用模式，缓存、队列、限流 |
| docker-compose | 7,100+ | Docker Compose 编排最佳实践，开发环境一键搭建 |
| kubernetes-deploy | 3,900+ | K8s 部署配置，Pod、Service、Ingress 管理 |&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;浏览器自动化&lt;/h2&gt;
&lt;p&gt;| Skill | 安装量 | 干嘛用的 |
|-------|--------|----------|
| agent-browser | 24,100+ | AI 帮你操作浏览器：自动点击、填表、截图、保持登录态 |
| puppeteer-scripts | 5,600+ | Puppeteer 爬虫脚本，数据抓取、PDF 生成 |
| playwright-testing | 4,200+ | Playwright 自动化测试，多端回归测试 |&lt;/p&gt;
&lt;p&gt;适合需要批量查数据、抓截图、自动化测试的重复性工作。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;SEO &amp;#x26; 营销&lt;/h2&gt;
&lt;p&gt;| Skill | 用途 |
|-------|------|
| seo-audit | 网站 SEO 体检：收录、速度、关键词、外链 |
| copywriting | 营销文案写作 |
| copy-editing | 文案润色 |
| pricing-strategy | 产品定价策略 |
| launch-strategy | 产品发布策略 |
| ab-test-setup | A/B 测试设计 |
| page-cro | 落地页转化优化 |
| signup-flow-cro | 注册流程优化 |
| email-sequence | 邮件营销序列 |
| social-content | 社交媒体内容 |
| paid-ads | 付费广告投放 |
| referral-program | 推荐计划设计 |
| marketing-psychology | 营销心理学 |
| competitor-analysis | 竞品分析框架，功能对比、定价策略、市场定位 |
| customer-interview | 用户访谈指南，挖掘真实需求、验证产品假设 |&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;中文内容创作&lt;/h2&gt;
&lt;p&gt;| Skill | 用途 |
|-------|------|
| baoyu-slide-deck | 生成 PPT |
| baoyu-article-illustrator | 文章配图 |
| baoyu-cover-image | 封面图 |
| baoyu-xhs-images | 小红书图片 |
| baoyu-comic | 漫画生成 |
| baoyu-post-to-wechat | 发布到公众号 |
| baoyu-post-to-x | 发布到 X |
| baoyu-infographic | 信息图 |
| notion-chinese | Notion 中文排版优化，目录、分栏、视觉美化 |
| wechat-mp-format | 公众号 Markdown 转富文本，自动处理代码块、引用样式 |&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;AI 开发 &amp;#x26; 提示工程&lt;/h2&gt;
&lt;p&gt;| Skill | 安装量 | 干嘛用的 |
|-------|--------|----------|
| prompt-engineering | 11,200+ | 提示词编写技巧，Few-shot、CoT、角色设定 |
| openai-integration | 9,500+ | OpenAI API 集成，流式输出、错误处理、重试机制 |
| langchain-patterns | 7,800+ | LangChain 开发模式，Chain、Agent、Memory 设计 |
| vector-search | 6,200+ | 向量检索实现，Embedding、相似度计算、RAG 架构 |
| fine-tuning-guide | 3,400+ | 模型微调流程，数据准备、训练参数、评估部署 |&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;文档处理&lt;/h2&gt;
&lt;p&gt;Anthropic 官方的 Office 套件：&lt;/p&gt;
&lt;p&gt;| Skill | 用途 |
|-------|------|
| pdf | 读取、提取、合并 PDF |
| docx | Word 文档处理 |
| pptx | PPT 生成和编辑 |
| xlsx | Excel 数据处理 |
| markdown-convert | Markdown 与各类格式互转，表格、公式、图表兼容 |&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;安全 &amp;#x26; 运维&lt;/h2&gt;
&lt;p&gt;| Skill | 安装量 | 干嘛用的 |
|-------|--------|----------|
| security-headers | 4,500+ | HTTP 安全头配置，CSP、HSTS、X-Frame-Options |
| dependency-audit | 3,800+ | 依赖漏洞扫描，npm/pip 包安全风险检查 |
| ci-cd-pipeline | 5,200+ | CI/CD 流水线设计，GitHub Actions、自动化部署 |
| monitoring-setup | 2,900+ | 监控告警配置，日志收集、指标采集、异常通知 |&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;其他&lt;/h2&gt;
&lt;p&gt;| Skill | 用途 |
|-------|------|
| skill-creator | 官方出的 Skill 编写教程，想自己造轮子的可以看 |
| git-workflow | Git 协作规范，分支策略、Commit 规范、Code Review |
| api-design | REST/GraphQL API 设计，版本控制、文档生成、错误处理 |&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>OpenClaw 源码分析</title><link>https://linme.cn/blog/ai/ai%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/ai%E5%8A%A9%E6%89%8B/openclaw-%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90</link><guid isPermaLink="true">https://linme.cn/blog/ai/ai%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/ai%E5%8A%A9%E6%89%8B/openclaw-%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90</guid><description>从 Gateway、工作区、技能、插件到多渠道架构，拆解 OpenClaw 仓库为什么会这么大。</description><pubDate>Wed, 18 Mar 2026 10:19:46 GMT</pubDate><content:encoded>&lt;h2&gt;先说结论&lt;/h2&gt;
&lt;p&gt;OpenClaw 这个仓库，不能把它理解成“一个 CLI 工具的源码”。&lt;/p&gt;
&lt;p&gt;更准确地说，它是一个 &lt;strong&gt;个人 AI 助手平台的 monorepo&lt;/strong&gt;，里面同时包含了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Gateway 守护进程&lt;/li&gt;
&lt;li&gt;浏览器 Control UI&lt;/li&gt;
&lt;li&gt;CLI&lt;/li&gt;
&lt;li&gt;多消息渠道接入层&lt;/li&gt;
&lt;li&gt;技能系统&lt;/li&gt;
&lt;li&gt;插件系统&lt;/li&gt;
&lt;li&gt;多设备节点能力&lt;/li&gt;
&lt;li&gt;模型认证与路由&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;项目整体定位&lt;/h2&gt;
&lt;p&gt;官方 README 对它的定位非常明确：&lt;br&gt;
OpenClaw 是一个运行在你自己设备上的个人 AI 助手，可以通过已经在用的渠道和它交互，而 Gateway 是控制平面。&lt;/p&gt;
&lt;p&gt;这句话其实就决定了整个仓库的结构：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;它必须有 &lt;strong&gt;常驻 Gateway&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;它必须有 &lt;strong&gt;多渠道适配&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;它必须有 &lt;strong&gt;浏览器和 CLI 控制面&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;它必须有 &lt;strong&gt;工作区 / 记忆 / 技能 / 插件&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;它必须有 &lt;strong&gt;设备节点和远程能力&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以 OpenClaw 的复杂度，不是因为“代码写乱了”，而是因为它要解决的问题本来就比普通代码 agent 大很多。&lt;/p&gt;
&lt;h2&gt;4 个核心概念&lt;/h2&gt;
&lt;h3&gt;1. Gateway&lt;/h3&gt;
&lt;p&gt;Gateway 是整个系统的中心。&lt;/p&gt;
&lt;p&gt;官方架构文档说明：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一个长期运行的 Gateway 持有所有消息面&lt;/li&gt;
&lt;li&gt;CLI、macOS app、Web UI 都通过 WebSocket 连接它&lt;/li&gt;
&lt;li&gt;节点设备也通过 WebSocket 连它&lt;/li&gt;
&lt;li&gt;默认端口是 &lt;code&gt;127.0.0.1:18789&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这意味着 OpenClaw 不是“每次输入命令就临时跑一下”的架构，而是：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;一个长期在线的 agent control plane&lt;/strong&gt;。&lt;/p&gt;
&lt;h3&gt;2. Agent Workspace&lt;/h3&gt;
&lt;p&gt;官方文档把 workspace 定义成“agent 的家”。&lt;/p&gt;
&lt;p&gt;默认位置：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;~/.openclaw/workspace
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它和 &lt;code&gt;~/.openclaw/&lt;/code&gt; 的区别很关键：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;~/.openclaw/&lt;/code&gt;
更偏系统状态、配置、凭据、会话&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.openclaw/workspace&lt;/code&gt;
更偏 agent 工作区、记忆、技能、上下文&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这套设计说明 OpenClaw 把“agent 的长期状态”当成一等公民，而不是把所有内容都塞进进程内存。&lt;/p&gt;
&lt;h3&gt;3. Skills&lt;/h3&gt;
&lt;p&gt;OpenClaw 的技能是 AgentSkills-compatible 的目录结构，本质是 &lt;code&gt;SKILL.md + frontmatter + 指令&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;这意味着它把“如何使用工具”这件事，显式建模成了可组合、可覆盖、可发布的技能系统，而不是全部硬编码在 prompt 里。&lt;/p&gt;
&lt;h3&gt;4. Plugins&lt;/h3&gt;
&lt;p&gt;插件是 OpenClaw 的另一条主线。&lt;/p&gt;
&lt;p&gt;官方插件文档写得很清楚，插件可以注册这些能力：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Gateway RPC&lt;/li&gt;
&lt;li&gt;HTTP routes&lt;/li&gt;
&lt;li&gt;Agent tools&lt;/li&gt;
&lt;li&gt;CLI commands&lt;/li&gt;
&lt;li&gt;Background services&lt;/li&gt;
&lt;li&gt;Context engines&lt;/li&gt;
&lt;li&gt;Skills&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;源码为什么会这么大&lt;/h2&gt;
&lt;p&gt;OpenClaw 仓库大，不是单一原因造成的，而是多块东西叠加出来的。&lt;/p&gt;
&lt;h3&gt;1. 多渠道接入&lt;/h3&gt;
&lt;p&gt;README 里列出的支持面非常多，像：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;WhatsApp&lt;/li&gt;
&lt;li&gt;Telegram&lt;/li&gt;
&lt;li&gt;Discord&lt;/li&gt;
&lt;li&gt;Slack&lt;/li&gt;
&lt;li&gt;Signal&lt;/li&gt;
&lt;li&gt;iMessage&lt;/li&gt;
&lt;li&gt;WebChat&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些渠道的接入方式、消息模型、授权模式、媒体处理都不一样。&lt;br&gt;
仅这一层就会拉高很多复杂度。&lt;/p&gt;
&lt;h3&gt;2. 多端节点能力&lt;/h3&gt;
&lt;p&gt;官方架构文档里还提到节点可以暴露：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;canvas.*&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;camera.*&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;screen.record&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;location.get&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;也就是说它不仅能“聊天”，还要能和宿主设备能力交互。&lt;/p&gt;
&lt;h3&gt;3. 插件和技能生态&lt;/h3&gt;
&lt;p&gt;当一个系统支持：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;内置能力&lt;/li&gt;
&lt;li&gt;外部插件&lt;/li&gt;
&lt;li&gt;工作区技能&lt;/li&gt;
&lt;li&gt;本地技能&lt;/li&gt;
&lt;li&gt;插件技能&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;它的目录和加载逻辑天然就会复杂起来。&lt;/p&gt;
&lt;h3&gt;4. 模型和认证系统&lt;/h3&gt;
&lt;p&gt;OpenClaw 不是只绑定一个模型提供商。&lt;br&gt;
它还支持模型认证、OAuth、API key、profile rotation、failover。&lt;/p&gt;
&lt;p&gt;这部分一旦做成通用平台，复杂度就会明显高于单模型工具。&lt;/p&gt;
&lt;h2&gt;仓库目录&lt;/h2&gt;
&lt;h3&gt;&lt;code&gt;src/&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;可以把它理解成核心运行时与主流程胶水层。&lt;br&gt;
像 Gateway、CLI 入口、主调度逻辑，通常会围绕这里展开。&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;packages/&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;更适合放共享模块、公共能力、可复用运行时单元。&lt;br&gt;
这类目录一般是 monorepo 的基础设施层。&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;extensions/&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;这是 OpenClaw 的重点目录之一。&lt;br&gt;
官方插件文档说明，很多功能是通过插件扩展进来的，所以这里很可能就是内置扩展与 provider / channel / tool 能力的核心承载位置。&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;skills/&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;这里可以理解成 OpenClaw 自带的技能包。&lt;br&gt;
这些技能负责教 agent 怎样用工具，而不是只靠系统提示死撑。&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;ui/&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;对应浏览器端 Control UI。&lt;br&gt;
文档明确写了它是一个小型 Vite + Lit 单页应用，由 Gateway 提供静态资源。&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;apps/&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;这里通常会承载宿主应用层，例如桌面端或其它更高层的运行壳。&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;docs/&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;官方文档本身也在仓库里。&lt;br&gt;
OpenClaw 的功能面太大，所以 docs 在这个项目里不是“附属品”，而是理解系统不可绕开的主入口。&lt;/p&gt;
&lt;h2&gt;OpenClaw 的运行链路&lt;/h2&gt;
&lt;p&gt;如果用一句话概括 OpenClaw 的主链路，大概是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;消息渠道 / Web UI / CLI 把输入交给 Gateway，Gateway 结合会话、工作区、技能、插件、模型与工具执行，再把结果回送到对应表面。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;可以把它大致拆成这样：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;用户输入
  ↓
渠道适配层 / Web UI / CLI
  ↓
Gateway
  ↓
会话路由 / Agent 选择 / 模型选择
  ↓
技能 + 工具 + 插件能力
  ↓
工作区 / 记忆 / 输出
  ↓
回到聊天界面、浏览器或消息渠道
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这套链路和 Codex / Claude Code 那种“终端内 agent”不是一个量级的问题。&lt;/p&gt;
&lt;h2&gt;Workspace&lt;/h2&gt;
&lt;p&gt;OpenClaw 的一个重要特点，是它明确区分了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;配置和凭据&lt;/li&gt;
&lt;li&gt;工作区和记忆&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;官方文档把 workspace 当成 agent 的 home，还建议把它作为 &lt;strong&gt;私有 Git 仓库&lt;/strong&gt; 备份。&lt;/p&gt;
&lt;p&gt;这意味着 OpenClaw 并不是把长期状态完全交给模型上下文，而是努力把 agent 的“长期记忆”落在磁盘上、文件上、目录结构上。&lt;/p&gt;
&lt;p&gt;这个思路非常工程化，也很适合长期运行的 personal assistant。&lt;/p&gt;
&lt;h2&gt;Skills 和 Plugins 的组合，是 OpenClaw 最像“平台”的地方&lt;/h2&gt;
&lt;p&gt;很多 agent 项目会在这两件事里偏一边：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;要么工具很多，但不会系统化成技能&lt;/li&gt;
&lt;li&gt;要么 prompt 很多，但缺少真正的插件边界&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;OpenClaw 两边都做了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Skills 负责“怎么教 agent 使用能力”&lt;/li&gt;
&lt;li&gt;Plugins 负责“怎么把能力接进系统”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;像一个：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;带插件宿主、技能加载器、工作区和控制平面的 AI 操作系统雏形&lt;/strong&gt;。&lt;/p&gt;
&lt;h2&gt;安全模型也影响了源码结构&lt;/h2&gt;
&lt;p&gt;OpenClaw 一旦接入真实消息渠道和设备能力，安全模型就不能是“随便跑”。&lt;/p&gt;
&lt;p&gt;从官方文档看，有几个安全点会直接影响架构：&lt;/p&gt;
&lt;h3&gt;1. DM pairing&lt;/h3&gt;
&lt;p&gt;默认未知发件人不会直接通过，先走配对流程。&lt;/p&gt;
&lt;h3&gt;2. Dashboard 是管理面&lt;/h3&gt;
&lt;p&gt;官方文档明确说 Control UI 是 admin surface，不能随便暴露公网。&lt;/p&gt;
&lt;h3&gt;3. Workspace 不是硬沙箱&lt;/h3&gt;
&lt;p&gt;文档特别提醒：workspace 是默认 cwd，不等于强隔离。&lt;br&gt;
如果你想要真正隔离，还要开启 sandbox。&lt;/p&gt;
&lt;p&gt;这些设计都会反过来影响配置、认证、会话和工具执行层的代码形态。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>OpenClaw 使用指南</title><link>https://linme.cn/blog/ai/ai%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/ai%E5%8A%A9%E6%89%8B/openclaw-%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97</link><guid isPermaLink="true">https://linme.cn/blog/ai/ai%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/ai%E5%8A%A9%E6%89%8B/openclaw-%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97</guid><description>安装 OpenClaw</description><pubDate>Wed, 18 Mar 2026 10:19:06 GMT</pubDate><content:encoded>&lt;h2&gt;安装 OpenClaw&lt;/h2&gt;
&lt;p&gt;官方当前推荐的安装方式是 &lt;strong&gt;安装脚本&lt;/strong&gt;。&lt;/p&gt;
&lt;h3&gt;macOS / Linux / WSL2&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl -fsSL https://openclaw.ai/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Windows PowerShell&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;iwr -useb https://openclaw.ai/install.ps1 | iex
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;文档里明确建议：Windows 场景优先用 &lt;strong&gt;WSL2&lt;/strong&gt;。&lt;/p&gt;
&lt;h2&gt;系统要求&lt;/h2&gt;
&lt;p&gt;根据官方最新文档：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Node 22 或更高&lt;/li&gt;
&lt;li&gt;支持 macOS、Linux、Windows&lt;/li&gt;
&lt;li&gt;如果从源码运行，还需要 &lt;code&gt;pnpm&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;第一次运行&lt;/h2&gt;
&lt;p&gt;安装完成后，官方推荐直接执行引导命令：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;openclaw onboard --install-daemon
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个命令会做几件事：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;配置模型认证&lt;/li&gt;
&lt;li&gt;配置 Gateway&lt;/li&gt;
&lt;li&gt;初始化工作区&lt;/li&gt;
&lt;li&gt;选择是否接入渠道&lt;/li&gt;
&lt;li&gt;安装并启动守护进程&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;完成后，可以先检查 Gateway 状态：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;openclaw gateway status
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;最快上手方式：先用浏览器 Control UI&lt;/h2&gt;
&lt;p&gt;官方文档给出的最快路径是直接打开浏览器控制台：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;openclaw dashboard
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;默认本地地址一般是：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;http://127.0.0.1:18789/
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;最基础的使用方式&lt;/h2&gt;
&lt;h3&gt;1. 启动引导&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;openclaw onboard --install-daemon
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. 检查 Gateway&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;openclaw gateway status
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. 打开浏览器控制台&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;openclaw dashboard
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. 前台运行 Gateway 做调试&lt;/h3&gt;
&lt;p&gt;如果你想本地排查问题，可以直接前台启动：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;openclaw gateway --port 18789
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;常见命令&lt;/h2&gt;
&lt;h3&gt;查看 Gateway 状态&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;openclaw gateway status
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;停止 Gateway&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;openclaw gateway stop
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;重启 Gateway&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;openclaw gateway restart
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;打开浏览器控制台&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;openclaw dashboard
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;查看日志&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;openclaw logs --follow
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;运行诊断&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;openclaw doctor
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;自动修复常见问题&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;openclaw doctor --repair
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;给目标发送测试消息&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;openclaw message send --target +1234567890 --message &quot;Hello from OpenClaw&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;直接让 agent 执行任务&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;openclaw agent --message &quot;Ship checklist&quot; --thinking high
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;模型和认证怎么配&lt;/h2&gt;
&lt;p&gt;官方推荐的方式仍然是：&lt;strong&gt;优先在 &lt;code&gt;openclaw onboard&lt;/code&gt; 里做认证&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;如果后面要补充新的模型提供商，也可以直接走命令：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;openclaw models auth login --provider &amp;#x3C;provider-id&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如 OpenAI Codex 这类支持 OAuth 的提供商，可以直接接入；&lt;br&gt;
Anthropic 则更建议走 &lt;strong&gt;API Key&lt;/strong&gt; 路线，而不是依赖订阅兼容方案。&lt;/p&gt;
&lt;p&gt;模型选择本身由 OpenClaw 的模型配置控制。&lt;br&gt;
文档建议把主模型设成能用到的最强一档，再给低成本场景加 fallback。&lt;/p&gt;
&lt;h2&gt;OpenClaw 的核心概念&lt;/h2&gt;
&lt;h3&gt;1. Gateway&lt;/h3&gt;
&lt;p&gt;Gateway 是 OpenClaw 的核心守护进程。&lt;br&gt;
它会长期运行，统一管理：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;消息渠道&lt;/li&gt;
&lt;li&gt;模型调用&lt;/li&gt;
&lt;li&gt;会话&lt;/li&gt;
&lt;li&gt;技能&lt;/li&gt;
&lt;li&gt;插件&lt;/li&gt;
&lt;li&gt;控制 UI&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;它默认监听本地 &lt;code&gt;127.0.0.1:18789&lt;/code&gt;。&lt;/p&gt;
&lt;h3&gt;2. Workspace&lt;/h3&gt;
&lt;p&gt;OpenClaw 的工作区默认在：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;~/.openclaw/workspace
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;官方文档明确强调：&lt;strong&gt;把它当作 agent 的私有记忆空间&lt;/strong&gt;。&lt;br&gt;
它和 &lt;code&gt;~/.openclaw/&lt;/code&gt; 不是一回事：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;~/.openclaw/&lt;/code&gt;
放配置、凭据、会话状态&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.openclaw/workspace&lt;/code&gt;
放 agent 工作区、技能、记忆和长期上下文&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3. Skills&lt;/h3&gt;
&lt;p&gt;OpenClaw 的技能本质上是 &lt;code&gt;SKILL.md&lt;/code&gt; 驱动的能力包，兼容 AgentSkills 格式。&lt;/p&gt;
&lt;p&gt;常见位置有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;bundled skills：安装自带&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.openclaw/skills&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;#x3C;workspace&gt;/skills&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果同名技能冲突，工作区里的优先级最高。&lt;/p&gt;
&lt;h3&gt;4. Plugins&lt;/h3&gt;
&lt;p&gt;OpenClaw 的扩展能力大量通过插件提供。&lt;br&gt;
插件可以注册：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Gateway RPC&lt;/li&gt;
&lt;li&gt;HTTP 路由&lt;/li&gt;
&lt;li&gt;Agent 工具&lt;/li&gt;
&lt;li&gt;CLI 命令&lt;/li&gt;
&lt;li&gt;后台服务&lt;/li&gt;
&lt;li&gt;技能目录&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;查看当前插件：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;openclaw plugins list
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装官方插件示例：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;openclaw plugins install @openclaw/voice-call
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;启用插件示例：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;openclaw plugins enable open-prose
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Slash Commands 怎么用&lt;/h2&gt;
&lt;p&gt;OpenClaw 支持两套命令体系：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/...&lt;/code&gt; slash commands&lt;/li&gt;
&lt;li&gt;&lt;code&gt;! &amp;#x3C;cmd&gt;&lt;/code&gt; 主机 bash 命令&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;比较常见的 slash commands / directives 包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/help&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/commands&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/status&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/model&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/compact&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/tts&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;而 bash 相关命令常见的是：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;! &amp;#x3C;command&gt;
!poll
!stop
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中 &lt;code&gt;! &amp;#x3C;command&gt;&lt;/code&gt; 更接近“让宿主机执行一个命令”。&lt;/p&gt;
&lt;h2&gt;配置文件在哪里&lt;/h2&gt;
&lt;p&gt;OpenClaw 的主配置文件是：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;~/.openclaw/openclaw.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它实际支持的是 JSON / JSON5 风格配置。&lt;br&gt;
官方文档里提到，很多情况下不用直接手改，而是优先用：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;openclaw onboard
openclaw configure
openclaw config get agents.defaults.workspace
openclaw config set agents.defaults.heartbeat.every &quot;2h&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样更不容易把配置搞乱。&lt;/p&gt;
&lt;h2&gt;安全方面&lt;/h2&gt;
&lt;p&gt;OpenClaw 不是普通的聊天玩具，它会接真实渠道、真实设备、真实自动化能力，所以安全一定要注意。&lt;/p&gt;
&lt;h3&gt;1. Dashboard 是管理面&lt;/h3&gt;
&lt;p&gt;官方文档明确写了，Control UI 是一个 &lt;strong&gt;admin surface&lt;/strong&gt;。&lt;br&gt;
不要随便公开暴露到公网。&lt;/p&gt;
&lt;p&gt;更稳妥的方式是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;本机 localhost&lt;/li&gt;
&lt;li&gt;Tailscale&lt;/li&gt;
&lt;li&gt;SSH 隧道&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. 工作区不是硬沙箱&lt;/h3&gt;
&lt;p&gt;文档里特别说明：workspace 只是默认 cwd，不等于绝对隔离。&lt;br&gt;
如果要强隔离，要单独启用 sandbox 配置。&lt;/p&gt;
&lt;h3&gt;3. 工作区建议私有 Git 备份&lt;/h3&gt;
&lt;p&gt;OpenClaw 官方建议把 workspace 当成私有记忆，用 &lt;strong&gt;私有仓库&lt;/strong&gt; 备份。&lt;br&gt;
但注意不要把 secrets 一起提交进去。&lt;/p&gt;
&lt;h3&gt;4. 不认识的插件和技能别乱装&lt;/h3&gt;
&lt;p&gt;因为插件和 skills 都能扩展 agent 的工具面，来源不明的第三方扩展要谨慎启用。&lt;/p&gt;
&lt;h2&gt;一个最小上手流程&lt;/h2&gt;
&lt;p&gt;第一次使用，建议按这个顺序来：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl -fsSL https://openclaw.ai/install.sh | bash
openclaw onboard --install-daemon
openclaw gateway status
openclaw dashboard
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;确认浏览器里能连上 Control UI 以后，再决定是否继续：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;接入 Telegram / Discord / WhatsApp&lt;/li&gt;
&lt;li&gt;配置模型&lt;/li&gt;
&lt;li&gt;加 skills&lt;/li&gt;
&lt;li&gt;装 plugins&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;升级和维护&lt;/h2&gt;
&lt;p&gt;OpenClaw 官方更新文档里反复强调一件事：&lt;br&gt;
&lt;strong&gt;升级后优先跑 &lt;code&gt;openclaw doctor&lt;/code&gt;&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;最实用的维护习惯是：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;openclaw doctor
openclaw gateway status
openclaw logs --follow
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果发现配置漂移、旧服务残留、认证异常或危险 DM 策略，&lt;code&gt;doctor&lt;/code&gt; 会给出修复建议。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>Claude Code 使用指南</title><link>https://linme.cn/blog/ai/ai%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/ai%E7%BB%88%E7%AB%AF/claude-code-%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97</link><guid isPermaLink="true">https://linme.cn/blog/ai/ai%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/ai%E7%BB%88%E7%AB%AF/claude-code-%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97</guid><description>安装 Claude Code</description><pubDate>Wed, 18 Mar 2026 10:18:31 GMT</pubDate><content:encoded>&lt;h2&gt;安装 Claude Code&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npm install -g @anthropic-ai/claude-code
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;安装完成后怎么启动&lt;/h2&gt;
&lt;p&gt;先进入你的项目目录：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cd your-project
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后直接启动：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;claude
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第一次运行时，Claude Code 会引导你完成登录。&lt;br&gt;
如果你想显式执行登录，也可以用：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;claude auth login
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;登录完成后，建议先确认版本：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;claude --version
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;官方当前支持的登录来源主要有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Anthropic Console&lt;/li&gt;
&lt;li&gt;Claude.ai 账号&lt;/li&gt;
&lt;li&gt;Amazon Bedrock&lt;/li&gt;
&lt;li&gt;Google Vertex AI&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;系统要求&lt;/h2&gt;
&lt;p&gt;根据官方当前文档，Claude Code 的基础要求大致是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;macOS 10.15+&lt;/li&gt;
&lt;li&gt;Ubuntu 20.04+ / Debian 10+&lt;/li&gt;
&lt;li&gt;Windows 10+（WSL 或 Git for Windows）&lt;/li&gt;
&lt;li&gt;至少 4GB 内存&lt;/li&gt;
&lt;li&gt;Node.js 18+&lt;/li&gt;
&lt;li&gt;需要联网&lt;/li&gt;
&lt;li&gt;最好使用 Bash、Zsh 或 Fish&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果你是 Linux 或 macOS 用户，直接终端安装最顺。&lt;br&gt;
如果你是 Windows 用户，优先用 WSL 会省很多兼容性问题。&lt;/p&gt;
&lt;h2&gt;最基础的使用方式&lt;/h2&gt;
&lt;h3&gt;1. 进入项目后直接对话&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;claude
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;接着在交互界面里直接提任务，比如：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;先解释这个项目的目录结构
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;修复首页搜索框在移动端换行错位的问题
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. 启动时就带上任务&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;claude &quot;解释这个项目的目录结构&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. 非交互模式&lt;/h3&gt;
&lt;p&gt;如果你只想跑一次然后退出，可以用：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;claude -p &quot;解释 src/utils/request.ts 的作用&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个模式很适合脚本化、CI 或快速查询。&lt;/p&gt;
&lt;h2&gt;常见使用场景&lt;/h2&gt;
&lt;p&gt;比如解释代码：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;claude &quot;解释 src/components/Header.tsx 的职责和调用关系&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;比如修 bug：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;claude &quot;修复评论组件在深色模式下按钮颜色错误的问题&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;比如补测试：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;claude &quot;给 userService 增加单元测试，并运行测试确认通过&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;比如处理日志或管道输入：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cat logs.txt | claude -p &quot;总结这份日志里的主要错误&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;常用 CLI 命令&lt;/h2&gt;
&lt;h3&gt;启动交互式会话&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;claude
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;带初始提示启动&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;claude &quot;explain this project&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;非交互执行后退出&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;claude -p &quot;explain this function&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;继续当前目录最近一次会话&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;claude -c
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;恢复指定会话&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;claude -r &quot;auth-refactor&quot; &quot;继续完成这个 PR&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;查看登录状态&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;claude auth status
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;更新 Claude Code&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;claude update
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;管理 MCP&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;claude mcp
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;查看子代理&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;claude agents
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;交互模式里怎么用&lt;/h2&gt;
&lt;p&gt;Claude Code 的强项在于它会在同一个终端会话里持续保留上下文。&lt;br&gt;
常见工作流一般是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;先让它分析问题&lt;/li&gt;
&lt;li&gt;再让它给出修改计划&lt;/li&gt;
&lt;li&gt;然后让它直接改代码&lt;/li&gt;
&lt;li&gt;最后要求它运行检查或测试&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;先阅读这个仓库，然后告诉我最值得先改的 3 个问题
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后继续：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;修复第一个问题，只修改必要文件，完成后运行 npm run check
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这种方式比直接说“帮我优化一下”稳定很多。&lt;/p&gt;
&lt;h2&gt;常用 Slash Commands&lt;/h2&gt;
&lt;p&gt;Claude Code 的交互界面支持大量 slash commands。比较常用的有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/help&lt;/code&gt;
查看帮助&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/compact&lt;/code&gt;
压缩上下文，适合长会话&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/config&lt;/code&gt;
查看或修改配置&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/memory&lt;/code&gt;
管理 &lt;code&gt;CLAUDE.md&lt;/code&gt; 和记忆文件&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/model&lt;/code&gt;
切换模型&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/permissions&lt;/code&gt;
查看或修改权限&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/review&lt;/code&gt;
发起代码审查&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/clear&lt;/code&gt;
清空当前对话&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/mcp&lt;/code&gt;
管理 MCP 连接&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/init&lt;/code&gt;
初始化项目记忆和说明文件&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/vim&lt;/code&gt;
进入 vim 风格输入模式&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果已经和 Claude Code 聊了很久，优先记住 &lt;code&gt;/compact&lt;/code&gt;。&lt;br&gt;
它对控制上下文膨胀非常有用。&lt;/p&gt;
&lt;h2&gt;配置文件怎么写&lt;/h2&gt;
&lt;p&gt;Claude Code 的配置核心是 &lt;code&gt;settings.json&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;常见位置有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户级：&lt;code&gt;~/.claude/settings.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;项目级共享：&lt;code&gt;.claude/settings.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;项目级本地：&lt;code&gt;.claude/settings.local.json&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;项目级配置适合团队共享规则；本地配置适合个人偏好，不建议提交到仓库。&lt;/p&gt;
&lt;p&gt;例如，一个很实用的权限限制配置可以写成这样：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;permissions&quot;: {
    &quot;deny&quot;: [
      &quot;Read(./.env)&quot;,
      &quot;Read(./.env.*)&quot;,
      &quot;Read(./secrets/**)&quot;,
      &quot;Read(./config/credentials.json)&quot;,
      &quot;Read(./build)&quot;
    ]
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个配置的作用是：让 Claude Code 直接看不到敏感文件，避免误读到密钥和环境变量。&lt;/p&gt;
&lt;h2&gt;CLAUDE.md 很重要&lt;/h2&gt;
&lt;p&gt;Claude Code 会自动读取 &lt;code&gt;CLAUDE.md&lt;/code&gt;，它是长期稳定工作流的核心。&lt;/p&gt;
&lt;p&gt;常见位置：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;项目级：&lt;code&gt;./CLAUDE.md&lt;/code&gt; 或 &lt;code&gt;./.claude/CLAUDE.md&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;用户级：&lt;code&gt;~/.claude/CLAUDE.md&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;适合写进去的内容包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;构建命令&lt;/li&gt;
&lt;li&gt;测试命令&lt;/li&gt;
&lt;li&gt;命名规范&lt;/li&gt;
&lt;li&gt;代码风格&lt;/li&gt;
&lt;li&gt;项目架构说明&lt;/li&gt;
&lt;li&gt;不允许修改的目录&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;你也可以直接让 Claude Code 生成一个起始版本：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;/init
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;官方文档说明，&lt;code&gt;/init&lt;/code&gt; 会根据当前项目自动生成初版 &lt;code&gt;CLAUDE.md&lt;/code&gt;，然后你再手工补充更细的规则。&lt;/p&gt;
&lt;h2&gt;自定义 Slash Commands&lt;/h2&gt;
&lt;p&gt;Claude Code 官方当前的可复用命令体系，核心是 &lt;strong&gt;custom slash commands&lt;/strong&gt;。&lt;/p&gt;
&lt;h3&gt;个人命令目录&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;~/.claude/commands/
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;项目命令目录&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;.claude/commands/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一个最小例子可以这样写：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-md&quot;&gt;---
description: 用图解方式解释代码
argument-hint: [file]
---

先用一个类比解释这个文件，再画一个 ASCII 图，最后分步骤讲清楚：$ARGUMENTS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;假设文件名是：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;.claude/commands/explain-code.md
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;那你在会话里就可以直接执行：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;/explain-code src/auth/login.ts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这套方式很适合沉淀高频动作，比如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/review-api&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/check-performance&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/summarize-diff&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Subagents 怎么用&lt;/h2&gt;
&lt;p&gt;如果希望 Claude 在复杂任务里自动分工，可以再配 &lt;strong&gt;subagents&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;常见位置：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;项目级：&lt;code&gt;.claude/agents/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;用户级：&lt;code&gt;~/.claude/agents/&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;官方推荐的最快方式不是手写，而是先在会话里执行：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;/agents
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后通过交互界面创建一个子代理。&lt;br&gt;
比如可以单独做一个 &lt;code&gt;code-reviewer&lt;/code&gt;，只负责审查安全性、可维护性和回归风险。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>Codex 使用指南</title><link>https://linme.cn/blog/ai/ai%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/ai%E7%BB%88%E7%AB%AF/codex-%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97</link><guid isPermaLink="true">https://linme.cn/blog/ai/ai%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/ai%E7%BB%88%E7%AB%AF/codex-%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97</guid><description>安装 Codex</description><pubDate>Wed, 18 Mar 2026 10:17:07 GMT</pubDate><content:encoded>&lt;h2&gt;安装 Codex&lt;/h2&gt;
&lt;p&gt;官方推荐通过 &lt;code&gt;npm&lt;/code&gt; 全局安装：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npm i -g @openai/codex
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装完成后，先检查版本：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;codex --version
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后直接启动：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;codex
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第一次运行时，Codex 会要求你登录。官方支持两种方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用 ChatGPT 账号登录&lt;/li&gt;
&lt;li&gt;使用 OpenAI API Key 登录&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;最基础的使用方式&lt;/h2&gt;
&lt;h3&gt;1. 进入项目目录再启动&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cd your-project
codex
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样 Codex 会以当前目录作为工作区，能够直接读取并修改这个项目里的文件。&lt;/p&gt;
&lt;h3&gt;2. 直接给一个任务&lt;/h3&gt;
&lt;p&gt;你可以在启动时就带上提示词：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;codex &quot;解释这个项目的目录结构&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;codex &quot;为这个项目补充一个登录接口的单元测试&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. 常见使用场景&lt;/h3&gt;
&lt;p&gt;比如让它解释代码：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;codex &quot;解释 src/utils/request.ts 的作用和调用链&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;比如让它修 bug：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;codex &quot;修复首页搜索框在移动端换行错位的问题&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;比如让它补测试：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;codex &quot;给 userService 增加测试，并运行测试确认通过&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;交互模式里怎么用&lt;/h2&gt;
&lt;p&gt;Codex CLI 默认会进入一个交互式终端界面。在这个模式下，你可以：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;连续追问&lt;/li&gt;
&lt;li&gt;查看它的计划&lt;/li&gt;
&lt;li&gt;审核它准备执行的命令&lt;/li&gt;
&lt;li&gt;看它修改后的 diff&lt;/li&gt;
&lt;li&gt;继续在同一个上下文里迭代&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;常用命令&lt;/h2&gt;
&lt;h3&gt;启动交互式会话&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;codex
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;指定目录运行&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;codex --cd ./my-project
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;指定模型&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;codex -m gpt-5.4
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;允许工作区写入&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;codex --sandbox workspace-write
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;关闭频繁确认，适合你自己完全信任的本地环境&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;codex --ask-for-approval never
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更稳妥的默认值通常是：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;codex --ask-for-approval on-request --sandbox workspace-write
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;会话恢复&lt;/h2&gt;
&lt;p&gt;Codex 会把本地会话记录保存下来，所以你下次可以继续之前的任务。&lt;/p&gt;
&lt;p&gt;恢复最近一次会话：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;codex resume --last
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;打开会话列表再选择：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;codex resume
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这对做大一点的重构很有用，不用每次都重新解释项目背景。&lt;/p&gt;
&lt;h2&gt;常用 Slash Commands&lt;/h2&gt;
&lt;p&gt;在 Codex 交互界面里输入 &lt;code&gt;/&lt;/code&gt;，可以看到内置命令。比较常用的有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/model&lt;/code&gt;
切换模型&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/permissions&lt;/code&gt;
调整权限策略&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/diff&lt;/code&gt;
查看当前修改差异&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/clear&lt;/code&gt;
清空当前会话界面&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/copy&lt;/code&gt;
复制最近一次输出&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/compact&lt;/code&gt;
压缩上下文，适合长对话&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/exit&lt;/code&gt;
退出 Codex&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/init&lt;/code&gt;
在当前目录生成 &lt;code&gt;AGENTS.md&lt;/code&gt; 模板&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果已经和 Codex 聊了很久，优先记住 &lt;code&gt;/compact&lt;/code&gt;，它能减少上下文膨胀。&lt;/p&gt;
&lt;h2&gt;推荐配置&lt;/h2&gt;
&lt;p&gt;Codex 的用户级配置文件在：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;~/.codex/config.toml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一个适合大多数前端/Node 项目的基础配置可以写成这样：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-toml&quot;&gt;model = &quot;gpt-5.4&quot;
approval_policy = &quot;on-request&quot;
sandbox_mode = &quot;workspace-write&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这三个配置的意思分别是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;model&lt;/code&gt;
默认模型&lt;/li&gt;
&lt;li&gt;&lt;code&gt;approval_policy&lt;/code&gt;
命令执行前的确认策略&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sandbox_mode&lt;/code&gt;
文件系统与命令访问权限&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果你只想对某个仓库生效，也可以在项目里放：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;.codex/config.toml
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;AGENTS.md 很重要&lt;/h2&gt;
&lt;p&gt;如果你希望 Codex 更稳定地按你的习惯做事，建议在仓库根目录加一个 &lt;code&gt;AGENTS.md&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-md&quot;&gt;# AGENTS.md

## Repository rules

- 修改前先阅读相关文件
- 改完后运行 npm run check
- 不要修改与当前任务无关的文件
- 新增依赖前先说明原因
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Codex 会在开始工作前读取这些说明。&lt;br&gt;
这比每次手动重复要求更有效。&lt;/p&gt;
&lt;h2&gt;给 Codex 接入 MCP&lt;/h2&gt;
&lt;p&gt;MCP 可以理解成“给 Codex 装外部工具”。&lt;br&gt;
比如你可以给它接文档、浏览器、设计工具、数据库代理等。&lt;/p&gt;
&lt;p&gt;官方给出的添加方式是：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;codex mcp add &amp;#x3C;server-name&gt; -- &amp;#x3C;command&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如接一个文档服务器：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;codex mcp add context7 -- npx -y @upstash/context7-mcp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看 MCP 配置：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;codex mcp --help
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果想在会话里查看当前可用 MCP，也可以使用：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;/mcp
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;实战建议&lt;/h2&gt;
&lt;h3&gt;1. 先让它分析，再让它修改&lt;/h3&gt;
&lt;p&gt;不要一上来就说“全改掉”。&lt;br&gt;
更稳的方式是先让它说明现状、问题点、修改计划，再开始动手。&lt;/p&gt;
&lt;h3&gt;2. 任务要具体&lt;/h3&gt;
&lt;p&gt;下面这种提示更有效：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;把 editor-studio 页面改成 GitHub Dark 风格，只改配色，不改结构，改完运行 npm run check
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而不是：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;帮我优化一下
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. 明确限制条件&lt;/h3&gt;
&lt;p&gt;比如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不要改接口&lt;/li&gt;
&lt;li&gt;不要新增依赖&lt;/li&gt;
&lt;li&gt;只改某几个文件&lt;/li&gt;
&lt;li&gt;改完必须跑测试&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些边界越清楚，Codex 输出越稳定。&lt;/p&gt;
&lt;h3&gt;4. 不要默认给它最高权限&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;danger-full-access&lt;/code&gt; 或完全免审批虽然爽，但风险也最大。&lt;br&gt;
大多数本地项目用 &lt;code&gt;workspace-write + on-request&lt;/code&gt; 就够了。&lt;/p&gt;
&lt;h2&gt;一个最小上手流程&lt;/h2&gt;
&lt;p&gt;第一次使用，你可以直接照这个流程来：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npm i -g @openai/codex
codex
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;登录完成后，在你的项目目录执行：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;codex &quot;先阅读这个项目，然后告诉我最值得先改进的 3 个问题&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;确认它理解项目后，再继续：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;codex &quot;修复第一个问题，只修改必要文件，并在完成后运行 npm run check&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;升级 Codex&lt;/h2&gt;
&lt;p&gt;官方建议定期升级：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npm i -g @openai/codex@latest
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;升级后再确认一下版本：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;codex --version
&lt;/code&gt;&lt;/pre&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>React &amp; Vue 发展演变历程</title><link>https://linme.cn/blog/qianduan/react--vue-%E5%8F%91%E5%B1%95%E6%BC%94%E5%8F%98%E5%8E%86%E7%A8%8B</link><guid isPermaLink="true">https://linme.cn/blog/qianduan/react--vue-%E5%8F%91%E5%B1%95%E6%BC%94%E5%8F%98%E5%8E%86%E7%A8%8B</guid><description>| 时间 | React 核心发展里程碑（细节版） | Vue 核心发展里程碑（细节版） |</description><pubDate>Sun, 01 Mar 2026 13:45:16 GMT</pubDate><content:encoded>&lt;p&gt;| 时间            | React 核心发展里程碑（细节版）                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        | Vue 核心发展里程碑（细节版）                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| :-------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| &lt;strong&gt;2013年&lt;/strong&gt;      | 1. 2013 年，React 在 JSConf US 演讲及随后 &lt;strong&gt;2013-06-05&lt;/strong&gt; 的官方博客中正式对外公开，最初用于解决 Facebook 内部复杂 UI 的组织与更新效率问题；2. 核心理念初步确立：&lt;strong&gt;组件化&lt;/strong&gt;、&lt;strong&gt;声明式渲染&lt;/strong&gt;、&lt;strong&gt;单向数据流倾向&lt;/strong&gt;，以及通过轻量 UI 描述进行高效更新；3. &lt;strong&gt;JSX 从一开始就是可选语法扩展&lt;/strong&gt;，不是 React 的硬性前提；早期重点仍然是 Web 端 UI 视图层能力。                                                                                                                                                                                                           | 1. 尤雨溪开始构思并实现 Vue 的早期原型，目标是在保留响应式和模板能力的同时，做到比当时主流框架更&lt;strong&gt;轻量、易上手、易嵌入&lt;/strong&gt;；2. 早期设计思路受到 Angular 响应式模板机制的启发，同时强调更低的心智负担；3. 此阶段仍属于原型探索期，尚未形成后来完整的版本体系与官方生态。                                                                                                                                                                                                                                                                 |
| &lt;strong&gt;2014年&lt;/strong&gt;      | 1. 发布 &lt;strong&gt;React 0.12&lt;/strong&gt;，对 API 与术语进行整理，&lt;code&gt;React.renderComponent&lt;/code&gt; 改为 &lt;code&gt;React.render&lt;/code&gt;，&lt;code&gt;isValidComponent&lt;/code&gt; 改为 &lt;code&gt;isValidElement&lt;/code&gt;；2. 组件模型和元素抽象进一步稳定，社区开始更清晰地区分“组件实例”和“React 元素”；3. DevTools 与开发体验持续改进，React 逐步从 Facebook 内部方案走向更广泛的社区采用。                                                                                                                                                                                                                                                     | 1. 2014 年初，Vue 首次公开亮相，并在年内发布 &lt;strong&gt;0.10&lt;/strong&gt;、&lt;strong&gt;0.11&lt;/strong&gt; 等早期版本；2. 核心特性逐渐成型：&lt;strong&gt;响应式数据绑定&lt;/strong&gt;、&lt;strong&gt;指令系统&lt;/strong&gt;、&lt;strong&gt;组件雏形&lt;/strong&gt;，采用基于 &lt;code&gt;Object.defineProperty&lt;/code&gt; 的响应式实现；3. 这一阶段仍&lt;strong&gt;没有虚拟 DOM&lt;/strong&gt;，更新机制以指令驱动的 DOM 绑定为主，主打“简单直接、低学习成本”。                                                                                                                                                                                                                                        |
| &lt;strong&gt;2015年&lt;/strong&gt;      | 1. &lt;strong&gt;2015-03-10&lt;/strong&gt;，发布 &lt;strong&gt;React 0.13&lt;/strong&gt;，正式支持 &lt;strong&gt;ES6 class components&lt;/strong&gt;；2. &lt;strong&gt;2015-03-26&lt;/strong&gt;，React Native 开源，提出 &lt;strong&gt;“Learn once, write anywhere”&lt;/strong&gt;，推动 React 向跨平台渲染能力扩展；3. &lt;strong&gt;2015-09&lt;/strong&gt;，&lt;strong&gt;React 0.14&lt;/strong&gt; 将 &lt;code&gt;react&lt;/code&gt; 与 &lt;code&gt;react-dom&lt;/code&gt; 拆分，分离核心抽象与 DOM 渲染器；4. 同期正式引入 &lt;strong&gt;stateless function components&lt;/strong&gt;，为后续函数组件和 Hooks 时代埋下基础。                                                                                                                                                                               | 1. &lt;strong&gt;2015-06-11&lt;/strong&gt;，发布 &lt;strong&gt;Vue 0.12 “Dragon Ball”&lt;/strong&gt;，组件语法更统一，&lt;code&gt;paramAttributes&lt;/code&gt; 更名为 &lt;code&gt;props&lt;/code&gt;，并引入&lt;strong&gt;异步组件&lt;/strong&gt;；2. &lt;strong&gt;2015-10-26&lt;/strong&gt;，发布 &lt;strong&gt;Vue 1.0 正式版 “Evangelion”&lt;/strong&gt;；3. Vue 1.0 统一并简化模板语法，加入 &lt;code&gt;v-on&lt;/code&gt; / &lt;code&gt;v-bind&lt;/code&gt; 简写，使用 &lt;code&gt;v-for&lt;/code&gt; 取代旧的 &lt;code&gt;v-repeat&lt;/code&gt;；4. &lt;code&gt;vue-loader&lt;/code&gt;、热更新、scoped CSS 等工具链能力显著增强，Vue 开始具备构建中小型 SPA 的完整基础。                                                                                                                                                |
| &lt;strong&gt;2016年&lt;/strong&gt;      | 1. &lt;strong&gt;2016-04-07&lt;/strong&gt;，发布 &lt;strong&gt;React 15.0&lt;/strong&gt;，标志着 React 从 0.x 阶段进入更稳定的主版本节奏；2. React 15 的重点是 &lt;strong&gt;DOM 渲染实现重写&lt;/strong&gt;：更接近原生 DOM 创建方式，减少额外包装，提升 SVG 与标准 DOM 属性支持；3. React 在工程稳定性、控制台警告、渲染一致性方面进一步打磨，生态采用率持续上升。                                                                                                                                                                                                                                                                     | 1. 2016 年，Vue 2.0 完成从设计到正式发布的跨越，&lt;strong&gt;10 月发布 Vue 2.0 正式版 “Ghost in the Shell”&lt;/strong&gt;；2. Vue 2.0 的关键升级是引入 &lt;strong&gt;虚拟 DOM&lt;/strong&gt;，在保留模板易用性的同时提升复杂组件树更新性能；3. 渲染层与响应式系统整体重构，SSR、render function、JSX 支持更完善；4. Vue 2 奠定了此后数年 Vue 主流生态的技术基础。                                                                                                                                                                                                                  |
| &lt;strong&gt;2017年&lt;/strong&gt;      | 1. &lt;strong&gt;2017-04-07&lt;/strong&gt;，&lt;strong&gt;React 15.5&lt;/strong&gt; 将 &lt;code&gt;React.PropTypes&lt;/code&gt; 与 &lt;code&gt;React.createClass&lt;/code&gt; 从核心包中拆出并标记废弃，推动核心包继续精简；2. &lt;strong&gt;2017-09-26&lt;/strong&gt;，发布 &lt;strong&gt;React 16.0&lt;/strong&gt;，底层全面切换到 &lt;strong&gt;Fiber 架构&lt;/strong&gt;，为可中断渲染、优先级调度等能力建立基础；3. React 16 带来 &lt;strong&gt;Error Boundaries&lt;/strong&gt;、&lt;strong&gt;Portals&lt;/strong&gt;、返回字符串/数组等能力；4. &lt;strong&gt;2017-11-28&lt;/strong&gt;，&lt;strong&gt;React 16.2&lt;/strong&gt; 正式加入 &lt;strong&gt;Fragments&lt;/strong&gt;，进一步减少无意义的 DOM 包裹层。                                                                                                                                           | 1. 2017 年是 Vue 2 生态快速成熟的一年，Vue Router、Vuex、单文件组件与工程化工作流逐步成为事实标准；2. “&lt;strong&gt;渐进式框架&lt;/strong&gt;”定位更加清晰，开发者可以只使用核心库，也可以按需叠加路由、状态管理和构建工具；3. Vue 在后台系统、中小型业务前端和企业级组件库场景中加速普及，社区影响力显著提升。                                                                                                                                                                                                                                               |
| &lt;strong&gt;2019年&lt;/strong&gt;      | 1. &lt;strong&gt;2019-02-06&lt;/strong&gt;，发布 &lt;strong&gt;React 16.8&lt;/strong&gt;，&lt;strong&gt;Hooks 正式稳定&lt;/strong&gt;；2. &lt;code&gt;useState&lt;/code&gt;、&lt;code&gt;useEffect&lt;/code&gt;、&lt;code&gt;useContext&lt;/code&gt; 等核心 Hooks 让函数组件具备承载状态与副作用逻辑的能力；3. Hooks 解决了类组件中 &lt;code&gt;this&lt;/code&gt;、生命周期逻辑分散、复用困难等长期痛点，推动 React 开发范式向函数式全面转移；4. 官方开始更明显地推荐函数组件与 Hooks，但类组件仍被保留并继续可用。                                                                                                                                                                                                              | 1. 2019 年进入 &lt;strong&gt;Vue 3 设计与 RFC 推进期&lt;/strong&gt;，核心目标是提升大型应用中的逻辑复用、类型推断与长期可维护性；2. 官方正式明确 &lt;strong&gt;Composition API&lt;/strong&gt; 方向，用更灵活的组合式写法改善 Options API 在复杂组件中的组织问题；3. Vue 3 的新响应式方案开始转向 &lt;strong&gt;Proxy&lt;/strong&gt;，以突破 Vue 2 在数组索引、属性新增删除等场景的局限；4. 这一年更准确的定位是“Vue 3 方案确立与实验推进”，而不是正式发布年。                                                                                                                                                |
| &lt;strong&gt;2020年&lt;/strong&gt;      | 1. &lt;strong&gt;2020-10-20&lt;/strong&gt;，发布 &lt;strong&gt;React 17.0&lt;/strong&gt;；2. React 17 &lt;strong&gt;没有新增开发者可见的重大功能&lt;/strong&gt;，核心任务是为未来版本做底层铺垫；3. 重点包括&lt;strong&gt;事件委托系统重构&lt;/strong&gt;、跨版本嵌套升级支持，以及更平滑的渐进式升级路径；4. 同年推出 &lt;strong&gt;新的 JSX Transform&lt;/strong&gt;，减少对显式 &lt;code&gt;import React&lt;/code&gt; 的依赖，改善构建体验。                                                                                                                                                                                                                                                               | 1. &lt;strong&gt;2020-09-18&lt;/strong&gt;，发布 &lt;strong&gt;Vue 3.0 正式版 “One Piece”&lt;/strong&gt;，完成内核级重构；2. 核心升级包括：使用 &lt;strong&gt;Proxy&lt;/strong&gt; 重写响应式系统、正式推出 &lt;strong&gt;Composition API&lt;/strong&gt;、强化 &lt;strong&gt;TypeScript&lt;/strong&gt; 支持；3. 同时引入更好的 tree-shaking、更小包体，以及对 &lt;strong&gt;Fragment、Teleport、Suspense&lt;/strong&gt; 等能力的支持；4. Vue 3 标志着 Vue 从“易用的响应式框架”进入“兼顾工程规模、类型能力与运行性能”的新阶段。                                                                                                                                                          |
| &lt;strong&gt;2022年&lt;/strong&gt;      | 1. &lt;strong&gt;2022-03-29&lt;/strong&gt;，发布 &lt;strong&gt;React 18.0&lt;/strong&gt;；2. 核心能力包括：&lt;strong&gt;automatic batching&lt;/strong&gt;、&lt;code&gt;startTransition&lt;/code&gt; / &lt;code&gt;useTransition&lt;/code&gt;、更完善的 &lt;strong&gt;streaming SSR + Suspense&lt;/strong&gt;；3. 新入口 &lt;code&gt;createRoot&lt;/code&gt; / &lt;code&gt;hydrateRoot&lt;/code&gt; 取代旧渲染方式，为新能力启用提供基础；4. 需要注意的是，React 18 不是“默认全局开启并发渲染”，而是通过新 API 与特性&lt;strong&gt;按需启用并发能力&lt;/strong&gt;；5. React Server Components 在这一阶段仍主要处于实验和框架集成推进期。                                                                                                                                      | 1. &lt;strong&gt;2022-02-07&lt;/strong&gt; 起，&lt;strong&gt;Vue 3 成为官方默认版本&lt;/strong&gt;，Vue 2 进入维护收尾阶段；2. &lt;strong&gt;2022-07-01&lt;/strong&gt;，发布 &lt;strong&gt;Vue 2.7 “Naruto”&lt;/strong&gt;，将 &lt;strong&gt;Composition API、&lt;code&gt;&amp;#x3C;script setup&gt;&lt;/code&gt;、CSS &lt;code&gt;v-bind&lt;/code&gt;&lt;/strong&gt; 等关键能力回移到 Vue 2；3. Vue 3 生态逐步稳定，&lt;strong&gt;Pinia、Vite、Volar、Vue Devtools 6&lt;/strong&gt; 等方案成为主流组合；4. 这一阶段 Vue 的重点从“核心切换”转向“生态全面完成 Vue 3 迁移”。                                                                                                                                                                        |
| &lt;strong&gt;2023年&lt;/strong&gt;      | 1. 2023 年 React 没有新的稳定大版本发布，但有两项重要进展：&lt;strong&gt;react.dev 新文档体系成熟&lt;/strong&gt;，以及 &lt;strong&gt;Canary 发布通道&lt;/strong&gt;正式启用；2. React 团队通过 Labs / Canary 持续推进 &lt;strong&gt;RSC、Actions、Compiler&lt;/strong&gt; 等下一阶段能力；3. 需要纠正的是：&lt;strong&gt;React 18.2.0 实际发布于 2022 年 6 月，不是 2023 年；&lt;code&gt;useId&lt;/code&gt;、&lt;code&gt;useDeferredValue&lt;/code&gt; 也不是 2023 年才新增。&lt;/strong&gt;                                                                                                                                                                                                                    | 1. &lt;strong&gt;2023-05-11&lt;/strong&gt;，发布 &lt;strong&gt;Vue 3.3 “Rurouni Kenshin”&lt;/strong&gt;，重点强化 &lt;code&gt;&amp;#x3C;script setup&gt;&lt;/code&gt; 与 TypeScript 开发体验；2. 3.3 带来 &lt;strong&gt;宏中的导入类型支持、泛型组件、&lt;code&gt;defineSlots&lt;/code&gt;、更易用的 &lt;code&gt;defineEmits&lt;/code&gt;&lt;/strong&gt;，并以实验形式提供 &lt;code&gt;defineModel&lt;/code&gt; 等能力；3. &lt;strong&gt;2023-12-28&lt;/strong&gt;，发布 &lt;strong&gt;Vue 3.4 “Slam Dunk”&lt;/strong&gt;，重写模板解析器、优化响应式触发精度，并让 &lt;strong&gt;&lt;code&gt;defineModel&lt;/code&gt; 稳定&lt;/strong&gt;；4. &lt;strong&gt;2023-12-31&lt;/strong&gt;，&lt;strong&gt;Vue 2 正式结束官方维护（EOL）&lt;/strong&gt;，Vue 生态全面进入 Vue 3 时代。                                                                                        |
| &lt;strong&gt;2024~2026年&lt;/strong&gt; | 1. &lt;strong&gt;2024-12-05&lt;/strong&gt;，发布 &lt;strong&gt;React 19 稳定版&lt;/strong&gt;，重点引入 &lt;strong&gt;Actions&lt;/strong&gt;、&lt;code&gt;useActionState&lt;/code&gt;、&lt;code&gt;useOptimistic&lt;/code&gt;、&lt;code&gt;useFormStatus&lt;/code&gt;、&lt;code&gt;use&lt;/code&gt; 等能力，并强化表单与异步提交流程；2. React 19 进一步完善服务端与客户端协同的全栈开发体验，和 Server Components 配套能力结合得更紧密；3. &lt;strong&gt;2025-10-07&lt;/strong&gt;，&lt;strong&gt;React Compiler v1.0&lt;/strong&gt; 稳定发布，推动自动化性能优化进入正式阶段；4. &lt;strong&gt;2026-02-24&lt;/strong&gt;，&lt;strong&gt;React Foundation&lt;/strong&gt; 正式成立，React 的治理进一步走向长期化、基金会化；5. 这一阶段 React 的核心方向是：&lt;strong&gt;服务端优先协作、编译器优化、全栈整合、进一步降低高性能开发门槛&lt;/strong&gt;。 | 1. 截至 &lt;strong&gt;2026-03-25&lt;/strong&gt;，Vue 官方已明确的重要后续核心里程碑是 &lt;strong&gt;Vue 3.5（2024-09-01）&lt;/strong&gt;；2. Vue 3.5 重点包括：&lt;strong&gt;响应式系统重构优化&lt;/strong&gt;、更好的 SSR 表现、&lt;strong&gt;Lazy Hydration&lt;/strong&gt;、&lt;code&gt;useId()&lt;/code&gt;、&lt;code&gt;useTemplateRef()&lt;/code&gt;、&lt;code&gt;onWatcherCleanup()&lt;/code&gt; 等；3. 其中响应式系统重构显著改善了内存占用与大规模深层响应式场景下的性能表现；4. 2024 至 2026 年间，Vue 持续沿 &lt;strong&gt;3.x 小版本迭代&lt;/strong&gt; 推进，重点聚焦于 &lt;strong&gt;SSR、类型体验、开发者体验、生态协同&lt;/strong&gt;；5. 这一阶段 Vue 的核心方向是：&lt;strong&gt;渐进式体验保持不变，同时继续补强性能、SSR 与现代工具链协同能力&lt;/strong&gt;。 |&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;补充说明&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;两者都起步于“更高效地组织和更新 UI”，但 React 更强调 &lt;strong&gt;声明式组件抽象、渲染器解耦、跨平台与全栈协作&lt;/strong&gt;，Vue 更强调 &lt;strong&gt;渐进式采用、模板易用性、开发效率与工程平衡&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;核心转折点可概括为：&lt;strong&gt;React 16（Fiber）&lt;/strong&gt;、&lt;strong&gt;React 16.8（Hooks）&lt;/strong&gt;、&lt;strong&gt;React 18（并发相关能力）&lt;/strong&gt;、&lt;strong&gt;React 19（Actions / 全栈协作）&lt;/strong&gt;；以及 &lt;strong&gt;Vue 2.0（虚拟 DOM）&lt;/strong&gt;、&lt;strong&gt;Vue 3.0（Proxy + Composition API）&lt;/strong&gt;、&lt;strong&gt;Vue 3.5（响应式与 SSR 再优化）&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;未来趋势上，两者都在向 &lt;strong&gt;SSR / 服务端协同、编译器辅助优化、更强 TypeScript 支持、更好的开发体验&lt;/strong&gt; 发展；React 更偏向 &lt;strong&gt;Server Components + Compiler + 全栈整合&lt;/strong&gt;，Vue 更偏向 &lt;strong&gt;渐进式升级 + SSR 能力增强 + Vite 生态协同&lt;/strong&gt;。&lt;/li&gt;
&lt;/ol&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>Proxy 深度监听与 Vue3 响应式</title><link>https://linme.cn/blog/%E5%89%8D%E7%AB%AF/vue/proxy-%E6%B7%B1%E5%BA%A6%E7%9B%91%E5%90%AC%E4%B8%8E-vue3-%E5%93%8D%E5%BA%94%E5%BC%8F</link><guid isPermaLink="true">https://linme.cn/blog/%E5%89%8D%E7%AB%AF/vue/proxy-%E6%B7%B1%E5%BA%A6%E7%9B%91%E5%90%AC%E4%B8%8E-vue3-%E5%93%8D%E5%BA%94%E5%BC%8F</guid><description>Proxy 深度监听与 Vue3 响应式</description><pubDate>Tue, 03 Feb 2026 01:15:35 GMT</pubDate><content:encoded>&lt;h2&gt;Proxy 深度监听与 Vue3 响应式&lt;/h2&gt;
&lt;hr&gt;
&lt;h2&gt;核心机制：懒递归代理&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function reactive(target) {
  return new Proxy(target, {
    get(target, key, receiver) {
      track(target, key);  // 依赖收集
      
      const result = Reflect.get(target, key, receiver);
      
      // 懒递归：访问时才深层代理
      return isObject(result) ? reactive(result) : result;
    },
    
    set(target, key, value, receiver) {
      const oldValue = target[key];
      const result = Reflect.set(target, key, value, receiver);
      
      if (hasChanged(value, oldValue)) {
        trigger(target, key);  // 触发更新
      }
      return result;
    }
  });
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;懒递归 vs 深度遍历&lt;/h2&gt;
&lt;p&gt;| Vue2（defineProperty） | Vue3（Proxy） |
|:---|:---|
| 初始化递归遍历所有属性 | 访问时才代理深层对象 |
| 新增属性需 &lt;code&gt;Vue.set&lt;/code&gt; | 自动支持新增/删除 |
| 数组重写 7 个方法 | 原生支持索引和 length |&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;依赖收集与触发&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// 全局状态
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);  // 组件订阅此属性
}

// 修改时触发
function trigger(target, key) {
  const depsMap = targetMap.get(target);
  if (!depsMap) return;
  
  depsMap.get(key)?.forEach(effect =&gt; effect());
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;使用示例&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const state = reactive({ 
  count: 0, 
  nested: { num: 1 } 
});

effect(() =&gt; {
  console.log(state.nested.num);  // 访问时自动代理 nested
});

state.nested.num++;  // 触发更新
state.newProp = 123; // 自动响应，无需 set
&lt;/code&gt;&lt;/pre&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>git 工作树（worktree）</title><link>https://linme.cn/blog/%E8%AE%A1%E7%AE%97%E6%9C%BA/git/git-%E5%B7%A5%E4%BD%9C%E6%A0%91worktree</link><guid isPermaLink="true">https://linme.cn/blog/%E8%AE%A1%E7%AE%97%E6%9C%BA/git/git-%E5%B7%A5%E4%BD%9C%E6%A0%91worktree</guid><description>git 工作树（worktree）</description><pubDate>Tue, 27 Jan 2026 22:23:21 GMT</pubDate><content:encoded/><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>大列表渲染卡顿时，React 项目里怎么优化？</title><link>https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/%E5%A4%A7%E5%88%97%E8%A1%A8%E6%B8%B2%E6%9F%93%E5%8D%A1%E9%A1%BF%E6%97%B6react-%E9%A1%B9%E7%9B%AE%E9%87%8C%E6%80%8E%E4%B9%88%E4%BC%98%E5%8C%96</link><guid isPermaLink="true">https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/%E5%A4%A7%E5%88%97%E8%A1%A8%E6%B8%B2%E6%9F%93%E5%8D%A1%E9%A1%BF%E6%97%B6react-%E9%A1%B9%E7%9B%AE%E9%87%8C%E6%80%8E%E4%B9%88%E4%BC%98%E5%8C%96</guid><description>满分答案</description><pubDate>Sun, 25 Jan 2026 10:14:03 GMT</pubDate><content:encoded>&lt;h2&gt;满分答案&lt;/h2&gt;
&lt;p&gt;大列表卡顿的核心原因是&lt;strong&gt;一次性渲染大量 DOM 节点&lt;/strong&gt;，阻塞主线程。
优化方案按优先级：&lt;strong&gt;虚拟滚动（核心）、懒加载、分页、列表项 memo 优化、减少渲染节点、时间切片、避免复杂计算&lt;/strong&gt;，其中&lt;strong&gt;虚拟滚动是解决超大数据量最有效的方案&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;一、卡顿的根本原因&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;一次性渲染成百上千个 DOM 节点&lt;/li&gt;
&lt;li&gt;主线程被 JS 执行阻塞，页面交互、滚动、输入都会卡顿&lt;/li&gt;
&lt;li&gt;重排重绘（reflow）成本极高&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h1&gt;二、React 项目实战优化方案（从必用到进阶）&lt;/h1&gt;
&lt;h2&gt;1. 虚拟滚动（最有效、首选）&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;只渲染可视区域内的节点&lt;/strong&gt;，可视区域外的 DOM 全部不渲染，节点数从 10000 → 10~20。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;成熟库（直接用）&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;react-window&lt;/code&gt;（轻量）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;react-virtualized&lt;/code&gt;（功能全）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;antd&lt;/code&gt; / &lt;code&gt;antd-table&lt;/code&gt; 自带 &lt;code&gt;virtual&lt;/code&gt; 属性&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import { FixedSizeList } from &apos;react-window&apos;;

const VirtualList = ({ data }) =&gt; {
  return (
    &amp;#x3C;FixedSizeList
      height={500}        // 可视区域高度
      width=&quot;100%&quot;
      itemCount={data.length}
      itemHeight={50}     // 每项高度
    &gt;
      {({ index, style }) =&gt; (
        &amp;#x3C;div style={style}&gt;{data[index]}&amp;#x3C;/div&gt;
      )}
    &amp;#x3C;/FixedSizeList&gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;2. 列表项使用 React.memo 缓存&lt;/h2&gt;
&lt;p&gt;防止父组件更新导致&lt;strong&gt;所有列表项重复渲染&lt;/strong&gt;。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;const Item = React.memo(({ item }) =&gt; {
  return &amp;#x3C;div&gt;{item.name}&amp;#x3C;/div&gt;;
});
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;3. 分页加载 / 滚动加载（懒加载）&lt;/h2&gt;
&lt;p&gt;不一次渲染所有数据：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;分页&lt;/li&gt;
&lt;li&gt;滚动到底加载更多（无限滚动）&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;useEffect(() =&gt; {
  // 监听滚动，触底加载下一页
  window.addEventListener(&apos;scroll&apos;, handleScroll);
}, []);
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;4. 使用正确、稳定的 key&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;千万不要用 index 做 key&lt;/strong&gt;，会导致：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;错误复用&lt;/li&gt;
&lt;li&gt;大量不必要的 DOM 销毁重建&lt;/li&gt;
&lt;li&gt;列表 Diff 极慢&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;// ✅ 正确
{item.id}

// ❌ 错误
{index}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;5. 时间切片（Time Slicing）&lt;/h2&gt;
&lt;p&gt;利用 React Fiber 把渲染任务&lt;strong&gt;分片执行&lt;/strong&gt;，不阻塞主线程：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ReactDOM.createRoot&lt;/code&gt;（React 18 默认开启）&lt;/li&gt;
&lt;li&gt;配合 &lt;code&gt;useDeferredValue&lt;/code&gt; / &lt;code&gt;Suspense&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import { useDeferredValue } from &apos;react&apos;;

const deferredList = useDeferredValue(list);
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;6. 减少列表项内部计算&lt;/h2&gt;
&lt;p&gt;用 &lt;code&gt;useMemo&lt;/code&gt; 缓存列表项内部的&lt;strong&gt;过滤、排序、格式化&lt;/strong&gt;。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;const content = useMemo(() =&gt; formatData(item), [item]);
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;7. 图片懒加载&lt;/h2&gt;
&lt;p&gt;列表中的图片延迟加载，减少渲染压力。&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;三、优化优先级&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;虚拟滚动&lt;/strong&gt;（1000条以上数据必用）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;分页/无限加载&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;列表项 memo 优化&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;稳定 key&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;时间切片（React 18）&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;减少内部计算 &amp;#x26; 图片懒加载&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h1&gt;四、一句话总结&lt;/h1&gt;
&lt;p&gt;大列表卡顿是因为&lt;strong&gt;一次性渲染太多 DOM&lt;/strong&gt;。
最优方案是&lt;strong&gt;虚拟滚动&lt;/strong&gt;，只渲染可视区域；
其次是&lt;strong&gt;分页、懒加载、memo 缓存、稳定 key&lt;/strong&gt;，
配合 React 18 &lt;strong&gt;时间切片&lt;/strong&gt;，可彻底解决卡顿问题。&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;万条数据不卡顿 = 虚拟滚动 + memo + 正确key + 时间切片&lt;/strong&gt;&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>React 中如何获取 DOM 节点？</title><link>https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/react-%E4%B8%AD%E5%A6%82%E4%BD%95%E8%8E%B7%E5%8F%96-dom-%E8%8A%82%E7%82%B9</link><guid isPermaLink="true">https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/react-%E4%B8%AD%E5%A6%82%E4%BD%95%E8%8E%B7%E5%8F%96-dom-%E8%8A%82%E7%82%B9</guid><description>满分答案</description><pubDate>Sun, 25 Jan 2026 10:10:05 GMT</pubDate><content:encoded>&lt;h2&gt;满分答案&lt;/h2&gt;
&lt;p&gt;在 React 中获取真实 DOM 节点，&lt;strong&gt;首选使用 useRef() 钩子&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;创建 ref 对象 → &lt;code&gt;const ref = useRef(null)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;绑定到元素上 → &lt;code&gt;&amp;#x3C;div ref={ref} /&gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;在 &lt;strong&gt;useEffect / 事件回调&lt;/strong&gt; 中通过 &lt;code&gt;ref.current&lt;/code&gt; 获取真实 DOM&lt;/li&gt;
&lt;li&gt;函数组件获取子组件 DOM，需搭配 &lt;code&gt;forwardRef&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h1&gt;一、最标准、最常用方法：&lt;strong&gt;useRef&lt;/strong&gt;&lt;/h1&gt;
&lt;h2&gt;1. 获取当前组件内的 DOM（最简单）&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import { useRef, useEffect } from &apos;react&apos;;

function App() {
  // 1. 创建 ref
  const domRef = useRef(null);

  // 2. DOM 渲染完成后才能拿到（ useEffect ）
  useEffect(() =&gt; {
    // 真实 DOM 节点
    console.log(domRef.current); 
    // 可以操作：聚焦、样式、获取宽高、滚动等
    domRef.current.focus();
  }, []);

  // 3. 绑定到元素
  return &amp;#x3C;input ref={domRef} /&gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h1&gt;二、获取子组件的 DOM 节点&lt;/h1&gt;
&lt;p&gt;子组件必须用 &lt;strong&gt;forwardRef&lt;/strong&gt; 把 ref 转发出去&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import { useRef, forwardRef } from &apos;react&apos;;

// 子组件
const Child = forwardRef((props, ref) =&gt; {
  return &amp;#x3C;div ref={ref}&gt;子组件 DOM&amp;#x3C;/div&gt;;
});

// 父组件
function Parent() {
  const childDomRef = useRef(null);

  useEffect(() =&gt; {
    console.log(childDomRef.current); // 拿到子组件的 div DOM
  }, []);

  return &amp;#x3C;Child ref={childDomRef} /&gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h1&gt;三、获取 DOM 的时机（非常重要）&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;渲染完成后获取&lt;/strong&gt; → useEffect（最安全）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;事件触发时获取&lt;/strong&gt; → 点击/输入等事件里&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;useLayoutEffect&lt;/strong&gt; → DOM 更新后、浏览器绘制前（获取布局）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;千万不要在组件渲染期间直接拿&lt;/strong&gt;，会是 null！&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;四、类组件写法（了解即可）&lt;/h1&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;class App extends React.Component {
  componentDidMount() {
    console.log(this.domRef);
  }
  render() {
    return &amp;#x3C;div ref={(el) =&gt; (this.domRef = el)} /&gt;;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h1&gt;五、总结&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;获取 DOM 统一用 useRef&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;绑定：ref={domRef}&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;获取：domRef.current&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;必须在 useEffect 或事件里拿&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h3&gt;一句话记忆&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;创建 ref → 绑定元素 → useEffect 里拿 current&lt;/strong&gt;&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>useContext 有什么使用场景和性能风险？</title><link>https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/usecontext-%E6%9C%89%E4%BB%80%E4%B9%88%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF%E5%92%8C%E6%80%A7%E8%83%BD%E9%A3%8E%E9%99%A9</link><guid isPermaLink="true">https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/usecontext-%E6%9C%89%E4%BB%80%E4%B9%88%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF%E5%92%8C%E6%80%A7%E8%83%BD%E9%A3%8E%E9%99%A9</guid><description>满分答案</description><pubDate>Sun, 25 Jan 2026 10:06:53 GMT</pubDate><content:encoded>&lt;h1&gt;满分答案&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;useContext 用于跨层级组件共享数据，解决 props 逐层传递问题；但只要 context 的 value 变化，所有使用该 context 的组件都会全部重渲染，容易造成大面积无效渲染，这是最大的性能风险。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;一、useContext 适用场景&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;全局通用状态&lt;/strong&gt;
主题（亮色/暗色）、语言、用户信息、全局配置&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;多层级传值&lt;/strong&gt;
爷→父→子→孙，不想一层层 props 透传&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;组件库内部状态共享&lt;/strong&gt;
表单、弹窗、步骤条等跨组件通信&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h1&gt;二、useContext 最大性能风险&lt;/h1&gt;
&lt;h3&gt;风险：&lt;strong&gt;value 一变，全体消费者重渲染！&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;只要 &lt;code&gt;Provider&lt;/code&gt; 的 &lt;code&gt;value&lt;/code&gt; 改变&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;所有用到 useContext(MyContext) 的组件都会重渲染&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;即使组件只用到一小部分数据，也会被迫渲染&lt;/li&gt;
&lt;li&gt;项目越大，性能浪费越严重&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;根本原因&lt;/h3&gt;
&lt;p&gt;React 对 &lt;code&gt;value&lt;/code&gt; 做&lt;strong&gt;引用比较（===）&lt;/strong&gt;
每次父组件渲染，若直接写：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;&amp;#x3C;MyContext.Provider value={{ a:1, b:2 }}&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;会创建&lt;strong&gt;新对象&lt;/strong&gt; → 引用变化 → 所有消费者重渲染。&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;三、如何避免性能问题？&lt;/h1&gt;
&lt;h2&gt;1. 拆分 Context&lt;/h2&gt;
&lt;p&gt;把&lt;strong&gt;经常变&lt;/strong&gt;和&lt;strong&gt;不经常变&lt;/strong&gt;的状态分开存放&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;&amp;#x3C;UserContext.Provider value={user}&gt;
  &amp;#x3C;ThemeContext.Provider value={theme}&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2. 用 useMemo 缓存 value&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;const value = useMemo(() =&gt; ({ user, theme }), [user, theme]);
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3. 组件结合 memo + 只取需要的值&lt;/h2&gt;
&lt;p&gt;让组件只在&lt;strong&gt;真正用到的数据变化&lt;/strong&gt;时才渲染&lt;/p&gt;
&lt;h2&gt;4. 复杂状态用状态库&lt;/h2&gt;
&lt;p&gt;Redux、Zustand、Jotai 等，它们可以&lt;strong&gt;精准更新&lt;/strong&gt;，不会全量渲染&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;四、满分总结&lt;/h1&gt;
&lt;h3&gt;场景：&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;跨层级共享全局状态（主题、语言、用户信息），解决 props 逐层传递。&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;性能风险：&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;context 的 value 变化会导致所有使用它的组件全部重渲染，造成大面积无效渲染。&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;优化：&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;拆分 Context、缓存 value、组件拆分、使用专业状态库。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;适用&lt;/strong&gt;：全局/跨层共享数据&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;风险&lt;/strong&gt;：value 变 → 所有消费者&lt;strong&gt;全量重渲染&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;优化&lt;/strong&gt;：拆分 + 缓存 + 专业状态库&lt;/li&gt;
&lt;/ul&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>react父子组件通信有哪些方式？</title><link>https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/react%E7%88%B6%E5%AD%90%E7%BB%84%E4%BB%B6%E9%80%9A%E4%BF%A1%E6%9C%89%E5%93%AA%E4%BA%9B%E6%96%B9%E5%BC%8F</link><guid isPermaLink="true">https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/react%E7%88%B6%E5%AD%90%E7%BB%84%E4%BB%B6%E9%80%9A%E4%BF%A1%E6%9C%89%E5%93%AA%E4%BA%9B%E6%96%B9%E5%BC%8F</guid><description>满分答案</description><pubDate>Sun, 25 Jan 2026 10:00:02 GMT</pubDate><content:encoded>&lt;h3&gt;满分答案&lt;/h3&gt;
&lt;p&gt;React 父子组件通信主要有四种核心方式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;父传子&lt;/strong&gt;：通过 props 直接传递数据；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;子传父&lt;/strong&gt;：父组件通过 props 传递回调函数，子组件调用并传参；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;父调用子组件方法/获取DOM&lt;/strong&gt;：使用 useRef + forwardRef，配合 useImperativeHandle 控制暴露内容；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;跨层级父子通信&lt;/strong&gt;：使用 Context API 避免 props 逐层透传。
兄弟组件通信则以父组件为中间媒介进行转发。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2&gt;一、最基础、最常用（90% 场景）&lt;/h2&gt;
&lt;h3&gt;1. 父 → 子：props 传值&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;// 父
&amp;#x3C;Child name=&quot;小明&quot; age={18} /&gt;

// 子
function Child({ name, age }) {
  return &amp;#x3C;div&gt;{name}&amp;#x3C;/div&gt;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. 子 → 父：props 传回调函数&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;// 父
const handleMsg = (msg) =&gt; console.log(msg)
&amp;#x3C;Child onSend={handleMsg} /&gt;

// 子
function Child({ onSend }) {
  return &amp;#x3C;button onClick={() =&gt; onSend(&quot;来自子组件&quot;)}&gt;发送&amp;#x3C;/button&gt;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;二、进阶用法（ref 相关）&lt;/h2&gt;
&lt;h3&gt;3. 父获取子实例 / 调用子方法&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;useRef&lt;/code&gt; + &lt;code&gt;forwardRef&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;// 父
const childRef = useRef(null)
const callChild = () =&gt; childRef.current.sayHi()

&amp;#x3C;Child ref={childRef} /&gt;

// 子
const Child = forwardRef((props, ref) =&gt; {
  const sayHi = () =&gt; alert(&quot;hello&quot;)
  return &amp;#x3C;div&gt;子组件&amp;#x3C;/div&gt;
})
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. 子可控暴露方法：useImperativeHandle&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;useImperativeHandle(ref, () =&gt; ({
  sayHi: () =&gt; alert(&quot;hello&quot;)
}))
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;三、跨层级通信&lt;/h2&gt;
&lt;h3&gt;5. Context API（爷孙/深层组件）&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;const MyContext = createContext()

// 父
&amp;#x3C;MyContext.Provider value={数据}&gt;
  &amp;#x3C;Child /&gt;
&amp;#x3C;/MyContext.Provider&gt;

// 后代组件
const data = useContext(MyContext)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;四、兄弟组件通信&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;兄弟A → 父 → 兄弟B&lt;/li&gt;
&lt;li&gt;本质还是：&lt;strong&gt;props + 回调函数&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>常见 Hooks 有哪些？分别适合什么场景？</title><link>https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/%E5%B8%B8%E8%A7%81-hooks-%E6%9C%89%E5%93%AA%E4%BA%9B%E5%88%86%E5%88%AB%E9%80%82%E5%90%88%E4%BB%80%E4%B9%88%E5%9C%BA%E6%99%AF</link><guid isPermaLink="true">https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/%E5%B8%B8%E8%A7%81-hooks-%E6%9C%89%E5%93%AA%E4%BA%9B%E5%88%86%E5%88%AB%E9%80%82%E5%90%88%E4%BB%80%E4%B9%88%E5%9C%BA%E6%99%AF</guid><description>一、最基础必备 Hooks</description><pubDate>Sun, 25 Jan 2026 09:49:16 GMT</pubDate><content:encoded>&lt;h2&gt;一、最基础必备 Hooks&lt;/h2&gt;
&lt;h3&gt;1. useState&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;作用&lt;/strong&gt;：定义组件&lt;strong&gt;状态变量&lt;/strong&gt;，修改状态触发视图更新&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;场景&lt;/strong&gt;：所有需要&lt;strong&gt;组件内状态管理&lt;/strong&gt;的地方
&lt;ul&gt;
&lt;li&gt;开关、计数器、表单输入、显示隐藏等&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;const [count, setCount] = useState(0)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. useEffect&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;作用&lt;/strong&gt;：处理&lt;strong&gt;副作用&lt;/strong&gt;（异步、DOM 操作、定时器、请求）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;场景&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;发送网络请求&lt;/li&gt;
&lt;li&gt;订阅/取消订阅&lt;/li&gt;
&lt;li&gt;操作真实 DOM&lt;/li&gt;
&lt;li&gt;定时器/延时器&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;useEffect(()=&gt;{
  // 请求、定时器
}, [])
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. useContext&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;作用&lt;/strong&gt;：跨组件共享数据，&lt;strong&gt;告别 props 层层传递&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;场景&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;全局主题、语言&lt;/li&gt;
&lt;li&gt;用户信息&lt;/li&gt;
&lt;li&gt;多层组件需要共享的数据&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;const value = useContext(MyContext)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;二、性能优化 Hooks&lt;/h2&gt;
&lt;h3&gt;4. useMemo&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;作用&lt;/strong&gt;：&lt;strong&gt;缓存计算结果&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;场景&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;耗时计算（过滤、排序大量数据）&lt;/li&gt;
&lt;li&gt;缓存对象/数组，防止子组件重渲染&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;const total = useMemo(()=&gt;count*1000, [count])
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;5. useCallback&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;作用&lt;/strong&gt;：&lt;strong&gt;缓存函数本身&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;场景&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;函数传递给子组件时&lt;/li&gt;
&lt;li&gt;配合 React.memo 防止子组件重复渲染&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;const handleClick = useCallback(()=&gt;{}, [])
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;6. React.memo&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;作用&lt;/strong&gt;：&lt;strong&gt;缓存整个组件&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;场景&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;子组件频繁被父组件触发重渲染&lt;/li&gt;
&lt;li&gt;纯展示组件，props 不变就不更新&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;const Child = React.memo(Child)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;三、DOM &amp;#x26; 引用 Hooks&lt;/h2&gt;
&lt;h3&gt;7. useRef&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;作用&lt;/strong&gt;：
&lt;ol&gt;
&lt;li&gt;获取&lt;strong&gt;真实 DOM 元素&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;存储&lt;strong&gt;不需要渲染的变量&lt;/strong&gt;（定时器 ID、上次值）&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;场景&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;获取 input、div 等 DOM&lt;/li&gt;
&lt;li&gt;存定时器、计数器，修改不触发渲染&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;const inputRef = useRef(null)
const timerRef = useRef(null)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;8. useLayoutEffect&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;作用&lt;/strong&gt;：&lt;strong&gt;DOM 更新后、浏览器绘制前同步执行&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;场景&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;需要&lt;strong&gt;获取 DOM 最新尺寸/位置&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;避免页面闪烁、布局抖动&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;useLayoutEffect(()=&gt;{
  // 读取 DOM 布局
}, [])
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;四、状态管理增强 Hooks&lt;/h2&gt;
&lt;h3&gt;9. useReducer&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;作用&lt;/strong&gt;：&lt;strong&gt;复杂状态逻辑&lt;/strong&gt;替代 useState&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;场景&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;状态多、逻辑复杂&lt;/li&gt;
&lt;li&gt;一个动作修改多个状态&lt;/li&gt;
&lt;li&gt;状态依赖之前的值&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;const [state, dispatch] = useReducer(reducer, initialState)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;10. useImperativeHandle&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;作用&lt;/strong&gt;：&lt;strong&gt;子组件向父组件暴露方法&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;场景&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;父组件调用子组件函数&lt;/li&gt;
&lt;li&gt;自定义表单组件、弹窗组件&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;useImperativeHandle(ref, () =&gt; ({
  open, close
}))
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h1&gt;超清晰总结表&lt;/h1&gt;
&lt;p&gt;| Hooks | 核心功能 | 最常用场景 |
|------|--------|----------|
| &lt;strong&gt;useState&lt;/strong&gt; | 状态管理 | 开关、输入、计数 |
| &lt;strong&gt;useEffect&lt;/strong&gt; | 副作用处理 | 请求、定时器、DOM 操作 |
| &lt;strong&gt;useContext&lt;/strong&gt; | 跨组件共享 | 全局主题、用户信息 |
| &lt;strong&gt;useMemo&lt;/strong&gt; | 缓存计算值 | 耗时计算、缓存对象/数组 |
| &lt;strong&gt;useCallback&lt;/strong&gt; | 缓存函数 | 函数传给子组件 |
| &lt;strong&gt;useRef&lt;/strong&gt; | 存储引用/DOM | 获取 DOM、存不渲染变量 |
| &lt;strong&gt;useReducer&lt;/strong&gt; | 复杂状态 | 多状态、复杂逻辑 |
| &lt;strong&gt;useLayoutEffect&lt;/strong&gt; | 同步布局 | 读取 DOM 尺寸、防闪烁 |&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;一句话记忆口诀&lt;/h1&gt;
&lt;p&gt;状态修改用&lt;code&gt;useState&lt;/code&gt;，
副作用用&lt;code&gt;useEffect&lt;/code&gt;，
跨组件传值&lt;code&gt;useContext&lt;/code&gt;，
缓存数值&lt;code&gt;useMemo&lt;/code&gt;，
缓存函数&lt;code&gt;useCallback&lt;/code&gt;，
获取 DOM 用&lt;code&gt;useRef&lt;/code&gt;。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>useMemo 和 useCallback 的区别是什么？</title><link>https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/usememo-%E5%92%8C-usecallback-%E7%9A%84%E5%8C%BA%E5%88%AB%E6%98%AF%E4%BB%80%E4%B9%88</link><guid isPermaLink="true">https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/usememo-%E5%92%8C-usecallback-%E7%9A%84%E5%8C%BA%E5%88%AB%E6%98%AF%E4%BB%80%E4%B9%88</guid><description>一句话终极结论</description><pubDate>Sun, 25 Jan 2026 09:40:26 GMT</pubDate><content:encoded>&lt;h2&gt;一句话终极结论&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;useMemo 缓存「函数返回的值」，useCallback 缓存「函数本身」&lt;/strong&gt;
两者都是为了&lt;strong&gt;防止重复创建引用&lt;/strong&gt;，解决 React 重复渲染问题。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;1. 核心对比表&lt;/h2&gt;
&lt;p&gt;| 特性 | useMemo | useCallback |
| :--- | :--- | :--- |
| &lt;strong&gt;缓存什么&lt;/strong&gt; | &lt;strong&gt;值 / 计算结果&lt;/strong&gt; | &lt;strong&gt;函数本身&lt;/strong&gt; |
| &lt;strong&gt;返回什么&lt;/strong&gt; | 计算好的&lt;strong&gt;数据&lt;/strong&gt; | 缓存后的&lt;strong&gt;函数&lt;/strong&gt; |
| &lt;strong&gt;解决问题&lt;/strong&gt; | 避免重复&lt;strong&gt;昂贵计算&lt;/strong&gt; | 避免子组件&lt;strong&gt;重复渲染&lt;/strong&gt; |
| &lt;strong&gt;触发时机&lt;/strong&gt; | 依赖变化时&lt;strong&gt;重新计算&lt;/strong&gt; | 依赖变化时&lt;strong&gt;更换函数引用&lt;/strong&gt; |
| &lt;strong&gt;等价写法&lt;/strong&gt; | &lt;code&gt;useCallback(fn, deps)&lt;/code&gt; ≈ &lt;code&gt;useMemo(() =&gt; fn, deps)&lt;/code&gt; | |&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;2. 代码直观对比&lt;/h2&gt;
&lt;h3&gt;① useCallback（缓存函数）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;给函数做缓存，保证函数引用不变&lt;/strong&gt;
主要用于&lt;strong&gt;传递给子组件的函数&lt;/strong&gt;，配合 &lt;code&gt;React.memo&lt;/code&gt; 防止子组件重渲染。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;// 缓存函数本身，依赖不变，函数地址就不变
const handleClick = useCallback(() =&gt; {
  console.log(count);
}, [count]); 

// 传递给子组件，引用不变 → 子组件不重渲染
&amp;#x3C;Child onClick={handleClick} /&gt; 
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;② useMemo（缓存值）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;给计算结果做缓存，避免每次渲染都重算&lt;/strong&gt;
主要用于&lt;strong&gt;耗时计算、对象、数组&lt;/strong&gt;。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;// 缓存计算出来的值，依赖不变，值就不变
const expensiveValue = useMemo(() =&gt; {
  return count * 1000; // 模拟耗时计算
}, [count]);

// 缓存对象，保证引用不变
const userInfo = useMemo(() =&gt; ({ name: &apos;Tom&apos;, age: 20 }), []);
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;3. 最核心的本质&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;React 靠「引用地址」判断是否变化&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;useCallback&lt;/strong&gt;：让&lt;strong&gt;函数地址&lt;/strong&gt;不变&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;useMemo&lt;/strong&gt;：让&lt;strong&gt;数据/对象地址&lt;/strong&gt;不变&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;地址不变 → &lt;code&gt;React.memo&lt;/code&gt; 判定 props 不变 → &lt;strong&gt;子组件不重渲染&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;4. 最佳使用场景&lt;/h2&gt;
&lt;h3&gt;✅ useCallback 场景&lt;/h3&gt;
&lt;p&gt;需要把&lt;strong&gt;函数传给子组件&lt;/strong&gt;时：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;const fetchData = useCallback(() =&gt; {
  axios.get(&apos;/api&apos;);
}, []);
// 传递给被 memo 包裹的子组件
&amp;#x3C;Table fetchData={fetchData} /&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;✅ useMemo 场景&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;耗时计算&lt;/strong&gt;（过滤、排序大量数据）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;传递给子组件的对象/数组&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;const options = useMemo(() =&gt; ({ pageSize: 10 }), []);
&amp;#x3C;Filter options={options} /&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;5. 满分答案&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;useCallback&lt;/strong&gt; 缓存&lt;strong&gt;函数本身&lt;/strong&gt;，用于优化&lt;strong&gt;子组件渲染&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;useMemo&lt;/strong&gt; 缓存&lt;strong&gt;计算结果&lt;/strong&gt;，用于优化&lt;strong&gt;重复计算&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;两者都是&lt;strong&gt;依赖驱动&lt;/strong&gt;，依赖不变，缓存就不变；&lt;/li&gt;
&lt;li&gt;核心目的都是&lt;strong&gt;保持引用地址稳定&lt;/strong&gt;，配合 React.memo 防止无效重渲染。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;想缓存函数&lt;/strong&gt; → 用 &lt;code&gt;useCallback&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;想缓存数据/计算值&lt;/strong&gt; → 用 &lt;code&gt;useMemo&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;都是&lt;strong&gt;性能优化工具&lt;/strong&gt;，不要滥用&lt;/li&gt;
&lt;/ul&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>React 组件为什么会重复渲染</title><link>https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/react-%E7%BB%84%E4%BB%B6%E4%B8%BA%E4%BB%80%E4%B9%88%E4%BC%9A%E9%87%8D%E5%A4%8D%E6%B8%B2%E6%9F%93</link><guid isPermaLink="true">https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/react-%E7%BB%84%E4%BB%B6%E4%B8%BA%E4%BB%80%E4%B9%88%E4%BC%9A%E9%87%8D%E5%A4%8D%E6%B8%B2%E6%9F%93</guid><description>一句话结论</description><pubDate>Sun, 25 Jan 2026 09:38:43 GMT</pubDate><content:encoded>&lt;h2&gt;一句话结论&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;React 组件默认：父组件渲染 → 所有子组件自动跟着渲染！
不管子组件的 props 变没变，都会重新渲染。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这就是 99% 的重复渲染来源。&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;一、组件重复渲染的 4 大核心原因&lt;/h1&gt;
&lt;h2&gt;1. &lt;strong&gt;父组件渲染，子组件默认无条件重渲染&lt;/strong&gt;（最常见）&lt;/h2&gt;
&lt;p&gt;React 没有自动给子组件做优化，&lt;strong&gt;父一更新，子全更&lt;/strong&gt;。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;function Parent() {
  const [a] = useState(0)
  return &amp;#x3C;Child /&gt; // 父渲染 → 子一定渲染
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2. &lt;strong&gt;自身 state 变化&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;只要执行 &lt;code&gt;setState&lt;/code&gt;，组件&lt;strong&gt;一定重渲染&lt;/strong&gt;。
即使值没变，也会渲染：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;setCount(1)
setCount(1) // 依然会触发渲染
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3. &lt;strong&gt;props 引用变化&lt;/strong&gt;（对象/数组/函数）&lt;/h2&gt;
&lt;p&gt;因为 React 用 &lt;strong&gt;=== 比较&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;&amp;#x3C;Child list={[1,2,3]} /&gt; // 每次都是新数组 → 子组件渲染
&amp;#x3C;Child fn={() =&gt; {}} /&gt;  // 每次都是新函数 → 子组件渲染
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;4. &lt;strong&gt;context  value 变化&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;只要 &lt;code&gt;context.Provider&lt;/code&gt; 的 value 变了
&lt;strong&gt;所有用到这个 context 的后代组件全部重渲染&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;二、最关键知识点：&lt;/h1&gt;
&lt;h2&gt;&lt;strong&gt;React 组件渲染 ≠ DOM 更新&lt;/strong&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;组件渲染 = 运行函数 / 生成 VDOM&lt;/li&gt;
&lt;li&gt;DOM 更新 = 真实改变页面&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;组件重复渲染 ≠ 页面卡&lt;/strong&gt;
但&lt;strong&gt;渲染太多 = 浪费性能 = 页面卡&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;三、如何判断组件在重复渲染？&lt;/h1&gt;
&lt;p&gt;加一句 console.log 就行：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;function Child() {
  console.log(&quot;子组件渲染了&quot;) // 打印多了就是重复渲染
  return &amp;#x3C;div&gt;&amp;#x3C;/div&gt;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h1&gt;四、如何解决重复渲染？（最实用）&lt;/h1&gt;
&lt;h2&gt;1. 子组件包 &lt;code&gt;React.memo()&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;让子组件只有 props 真正变化时才渲染&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;const Child = React.memo(function Child() { ... })
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2. 用 &lt;code&gt;useMemo&lt;/code&gt; 缓存对象/数组&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;const list = useMemo(() =&gt; [1,2,3], [])
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3. 用 &lt;code&gt;useCallback&lt;/code&gt; 缓存函数&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;const fn = useCallback(() =&gt; { ... }, [])
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;4. 拆分组件&lt;/h2&gt;
&lt;p&gt;把&lt;strong&gt;会变的 state&lt;/strong&gt; 和&lt;strong&gt;不变的 UI&lt;/strong&gt; 拆分开。&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;总结&lt;/h1&gt;
&lt;p&gt;React 组件重复渲染主要有 4 个原因：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;父组件渲染，子组件默认无条件重渲染&lt;/strong&gt;（最主要）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自身 state 被更新&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;props 是引用类型（对象/数组/函数），每次都创建新引用&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;使用的 context value 发生变化&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;优化方式：
&lt;code&gt;React.memo&lt;/code&gt;、&lt;code&gt;useMemo&lt;/code&gt;、&lt;code&gt;useCallback&lt;/code&gt;、组件拆分。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;父渲染 → 子默认渲染&lt;/strong&gt;
&lt;strong&gt;引用变化 → 子一定渲染&lt;/strong&gt;
&lt;strong&gt;自身 setState → 自身一定渲染&lt;/strong&gt;&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>useState 更新为什么看起来有时是异步的？</title><link>https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/usestate-%E6%9B%B4%E6%96%B0%E4%B8%BA%E4%BB%80%E4%B9%88%E7%9C%8B%E8%B5%B7%E6%9D%A5%E6%9C%89%E6%97%B6%E6%98%AF%E5%BC%82%E6%AD%A5%E7%9A%84</link><guid isPermaLink="true">https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/usestate-%E6%9B%B4%E6%96%B0%E4%B8%BA%E4%BB%80%E4%B9%88%E7%9C%8B%E8%B5%B7%E6%9D%A5%E6%9C%89%E6%97%B6%E6%98%AF%E5%BC%82%E6%AD%A5%E7%9A%84</guid><description>一句话结论：</description><pubDate>Sat, 24 Jan 2026 14:48:24 GMT</pubDate><content:encoded>&lt;p&gt;一句话结论：
&lt;strong&gt;useState 更新本身不是异步函数，但它是「批量延迟执行」的，所以代码写起来感觉像异步。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;1. 先看最经典的迷惑代码&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const [count, setCount] = useState(0)

function handleClick() {
  console.log(count) // 0
  setCount(count + 1)
  console.log(count) // 还是 0！！！
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;明明调用了 &lt;code&gt;setCount&lt;/code&gt;，但值&lt;strong&gt;立刻拿不到最新的&lt;/strong&gt;，这就是「看起来异步」。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;2. 真正原因：闭包 + 队列机制&lt;/h2&gt;
&lt;h3&gt;核心 1：useState 是&lt;strong&gt;快照式&lt;/strong&gt;的&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;每次组件渲染，&lt;strong&gt;state 都是一个独立的快照&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;事件函数里拿到的 count，&lt;strong&gt;永远是本次渲染的旧值&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;调用 &lt;code&gt;setCount&lt;/code&gt; 不会修改当前快照，只会&lt;strong&gt;触发下一次渲染&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;核心 2：React 会&lt;strong&gt;合并、延迟更新&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;React 为了性能，不会一调用 &lt;code&gt;setState&lt;/code&gt; 就立刻更新：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;把更新&lt;strong&gt;放进队列&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;等当前函数执行完&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;再&lt;strong&gt;批量更新 state&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;最后&lt;strong&gt;重新渲染组件&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;所以：
&lt;strong&gt;在 set 之后立刻打印，拿到的还是「旧快照」。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;3. 一句话总结原理&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;不是异步，是闭包快照 + 批量延迟更新 → 导致不能同步拿到最新值。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;它和真正的异步（Promise/定时器）&lt;strong&gt;完全不是一回事&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;4. 3 种场景帮你彻底理解&lt;/h2&gt;
&lt;h3&gt;场景 1：同步事件里（看起来异步）&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;setCount(1)
console.log(count) // 旧值
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ 原因：&lt;strong&gt;更新被延后了&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;场景 2：set 传函数（立刻用最新值）&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;setCount(prev =&gt; prev + 1) // 这个能拿到最新值
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ 原因：&lt;strong&gt;函数式更新不依赖当前快照&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;场景 3： useEffect 里（能拿到最新值）&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;useEffect(()=&gt;{
  console.log(count) // 最新值
},[count])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ 原因：&lt;strong&gt;渲染完成后才执行&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;5. 超级好记的口诀&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;State 是快照，更新会排队；
当前拿不到，下次渲染见。
想立刻用值，就传函数式。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;useState 更新&lt;strong&gt;不是异步&lt;/strong&gt;，而是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;state 是 immutable 不可变的&lt;/strong&gt;，每次渲染都是独立快照&lt;/li&gt;
&lt;li&gt;&lt;code&gt;setState&lt;/code&gt; 只会把更新&lt;strong&gt;加入队列&lt;/strong&gt;，不会立即修改当前值&lt;/li&gt;
&lt;li&gt;React 为了性能会&lt;strong&gt;批量合并更新&lt;/strong&gt;，等同步代码执行完才统一更新、重渲染&lt;/li&gt;
&lt;li&gt;所以在同步代码里&lt;strong&gt;无法立即获取最新 state&lt;/strong&gt;，看起来像异步&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;不是异步，是批量延迟 + 闭包快照&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;当前渲染的 state 永远不变&lt;/li&gt;
&lt;li&gt;想立即用最新值：&lt;strong&gt;函数式更新&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;想监听最新值：&lt;strong&gt;useEffect&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;需要我给你演示&lt;strong&gt;如何立刻拿到最新 state&lt;/strong&gt;的 3 种正确写法吗？&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>React 和 Vue 的核心区别是什么？</title><link>https://linme.cn/blog/qianduan/react-%E5%92%8C-vue-%E7%9A%84%E6%A0%B8%E5%BF%83%E5%8C%BA%E5%88%AB%E6%98%AF%E4%BB%80%E4%B9%88</link><guid isPermaLink="true">https://linme.cn/blog/qianduan/react-%E5%92%8C-vue-%E7%9A%84%E6%A0%B8%E5%BF%83%E5%8C%BA%E5%88%AB%E6%98%AF%E4%BB%80%E4%B9%88</guid><description>一句话总纲</description><pubDate>Sat, 24 Jan 2026 14:43:44 GMT</pubDate><content:encoded>&lt;h2&gt;一句话总纲&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;React 是「函数式+数据驱动」，Vue 是「响应式+视图驱动」&lt;/strong&gt;
一个靠&lt;strong&gt;重新渲染&lt;/strong&gt;更新，一个靠&lt;strong&gt;精准劫持&lt;/strong&gt;更新。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;1. 数据响应式原理（最核心区别）&lt;/h2&gt;
&lt;h3&gt;React&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;数据不可变（Immutable 思想）&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;状态更新必须用 &lt;code&gt;setState&lt;/code&gt; / &lt;code&gt;useState&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;不会劫持数据&lt;/strong&gt;，状态变了 → &lt;strong&gt;重新执行组件函数&lt;/strong&gt; → 生成新 VDOM&lt;/li&gt;
&lt;li&gt;靠 &lt;strong&gt;diff 对比&lt;/strong&gt; 找到变化&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Vue&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;数据响应式劫持&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Vue2：&lt;code&gt;Object.defineProperty&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Vue3：&lt;code&gt;Proxy&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自动追踪依赖&lt;/strong&gt;，数据变了 → &lt;strong&gt;精确通知对应组件/节点更新&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;不需要手动 setState，直接修改数据&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;口诀&lt;/strong&gt;：
React 是&lt;strong&gt;暴力重渲染&lt;/strong&gt;，Vue 是&lt;strong&gt;精准点对点更新&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;2. 模板与渲染写法&lt;/h2&gt;
&lt;h3&gt;React&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;JSX 一统天下&lt;/strong&gt;（JS + HTML 混合）&lt;/li&gt;
&lt;li&gt;一切都是 JS，循环用 &lt;code&gt;map&lt;/code&gt;，条件用 &lt;code&gt;if/&amp;#x26;&amp;#x26;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;灵活度极高，贴近原生 JS&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Vue&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;模板（template）+ 脚本（script）分离&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;内置指令：&lt;code&gt;v-if&lt;/code&gt; / &lt;code&gt;v-for&lt;/code&gt; / &lt;code&gt;v-model&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;上手更简单，对新手友好&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;口诀&lt;/strong&gt;：
React &lt;strong&gt;All in JS&lt;/strong&gt;，Vue &lt;strong&gt;模板更直观&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;3. 组件更新机制&lt;/h2&gt;
&lt;h3&gt;React&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;自动重新渲染&lt;/strong&gt;：父组件更新 → 子组件默认全部跟着更新&lt;/li&gt;
&lt;li&gt;需要手动优化：&lt;code&gt;React.memo&lt;/code&gt; / &lt;code&gt;useMemo&lt;/code&gt; / &lt;code&gt;useCallback&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;渲染量大 → 所以需要 &lt;strong&gt;Fiber 架构&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Vue&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;组件自动追踪依赖&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;数据变 → 只更新用到这个数据的组件&lt;/li&gt;
&lt;li&gt;组件更新&lt;strong&gt;默认优化好&lt;/strong&gt;，基本不需要手动优化&lt;/li&gt;
&lt;li&gt;渲染量极小 → 不需要 Fiber&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;口诀&lt;/strong&gt;：
React &lt;strong&gt;需要手动优化&lt;/strong&gt;，Vue &lt;strong&gt;自带优化躺平用&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;4. 设计哲学与生态&lt;/h2&gt;
&lt;h3&gt;React&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;函数式编程（FP）&lt;/li&gt;
&lt;li&gt;专注 &lt;strong&gt;UI 层&lt;/strong&gt;，路由、状态管理靠社区（React Router / Redux / Zustand）&lt;/li&gt;
&lt;li&gt;自由度极高，适合大型项目、团队定制&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Vue&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;渐进式框架&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;全家桶一站式&lt;/strong&gt;（Vue Router / Pinia 官方内置）&lt;/li&gt;
&lt;li&gt;开箱即用，约束更强，开发效率高&lt;/li&gt;
&lt;li&gt;更适合中后台、快速开发&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;响应式不同&lt;/strong&gt;：React 靠 setState 重新渲染，Vue 靠 Proxy 自动劫持精准更新。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;渲染机制不同&lt;/strong&gt;：React 父更新子必更新，需要手动优化；Vue 自动追踪依赖，自带优化。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;写法不同&lt;/strong&gt;：React 用 JSX，一切皆 JS；Vue 用模板 + 指令，更易上手。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;架构不同&lt;/strong&gt;：React 渲染量大，需要 Fiber 防止卡顿；Vue 更新精准，不需要 Fiber。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;React&lt;/strong&gt;：灵活、函数式、全靠 JS、需要手动优化、有 Fiber&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vue&lt;/strong&gt;：简单、响应式、模板友好、自动优化、无需 Fiber&lt;/li&gt;
&lt;/ul&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>react为什么需要虚拟 DOM？</title><link>https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/react%E4%B8%BA%E4%BB%80%E4%B9%88%E9%9C%80%E8%A6%81%E8%99%9A%E6%8B%9F-dom</link><guid isPermaLink="true">https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/react%E4%B8%BA%E4%BB%80%E4%B9%88%E9%9C%80%E8%A6%81%E8%99%9A%E6%8B%9F-dom</guid><description>满分答案</description><pubDate>Fri, 23 Jan 2026 10:17:29 GMT</pubDate><content:encoded>&lt;h1&gt;满分答案&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;虚拟 DOM 就是用普通 JS 对象模拟真实 DOM 树。它的核心价值是：批量、高效更新视图，避免直接操作 DOM 带来的性能损耗，同时实现跨平台渲染，并让开发者专注于数据和UI。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;一、核心原因&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;真实 DOM 操作非常昂贵、慢&lt;/strong&gt;
真实 DOM 节点属性非常多，频繁操作、修改、重排重绘会严重卡顿。
虚拟 DOM 是轻量 JS 对象，操作极快。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;实现 DOM 批量更新，减少重排重绘&lt;/strong&gt;
虚拟 DOM 不会立即操作 DOM，而是在内存中做 diff，&lt;strong&gt;收集所有变更后一次性更新真实 DOM&lt;/strong&gt;，把多次 DOM 操作合并成一次。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;提供跨平台能力（React 最关键）&lt;/strong&gt;
虚拟 DOM 是一层抽象，不依赖浏览器环境
→ 可渲染成小程序、React Native、桌面端
→ &lt;strong&gt;一次编写，多端运行&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;声明式开发，不用手动操作 DOM&lt;/strong&gt;
只需要关心数据变化，React 自动更新 UI
代码更简洁、可维护性更强&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2&gt;二、通俗理解&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;真实 DOM = 复杂、笨重、操作慢&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;虚拟 DOM = 轻量、简单、纯 JS 对象&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Diff 算法 = 只改变化的部分&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;虚拟 DOM 相当于&lt;strong&gt;真实 DOM 的“草稿纸”&lt;/strong&gt;，先在草稿纸上改好，再一次性誊写到 DOM 上。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;三、虚拟 DOM 工作流程&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;状态更新 → 生成&lt;strong&gt;新虚拟 DOM&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;和&lt;strong&gt;旧虚拟 DOM&lt;/strong&gt; 做 diff&lt;/li&gt;
&lt;li&gt;找到&lt;strong&gt;最小差异&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;一次性更新真实 DOM&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2&gt;四、满分总结&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;真实 DOM 操作性能差&lt;/strong&gt;，虚拟 DOM 是轻量对象，操作更快；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;批量更新 DOM&lt;/strong&gt;，减少重排重绘，提升性能；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;跨平台渲染&lt;/strong&gt;，支持 React Native、小程序等；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;声明式编程&lt;/strong&gt;，让开发者不用手动操作 DOM，专注业务。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h3&gt;一句话终极记忆&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;虚拟 DOM = 用 JS 对象模拟 DOM → 批量更新 → 高性能 → 跨平台&lt;/strong&gt;&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>函数组件和类组件的区别是什么？</title><link>https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/%E5%87%BD%E6%95%B0%E7%BB%84%E4%BB%B6%E5%92%8C%E7%B1%BB%E7%BB%84%E4%BB%B6%E7%9A%84%E5%8C%BA%E5%88%AB%E6%98%AF%E4%BB%80%E4%B9%88</link><guid isPermaLink="true">https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/%E5%87%BD%E6%95%B0%E7%BB%84%E4%BB%B6%E5%92%8C%E7%B1%BB%E7%BB%84%E4%BB%B6%E7%9A%84%E5%8C%BA%E5%88%AB%E6%98%AF%E4%BB%80%E4%B9%88</guid><description>满分答案</description><pubDate>Thu, 22 Jan 2026 10:12:14 GMT</pubDate><content:encoded>&lt;h1&gt;满分答案&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;函数组件使用 Hooks 管理状态与副作用，代码更简洁、逻辑更易复用；类组件使用 class、this、生命周期，代码冗余且难以优化。
React 官方推荐函数组件，未来趋势完全以函数组件为主。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;一、核心区别（最清晰对比）&lt;/h1&gt;
&lt;h2&gt;1. 编写方式&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;函数组件&lt;/strong&gt;：普通 JS 函数，返回 JSX&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;类组件&lt;/strong&gt;：继承 &lt;code&gt;React.Component&lt;/code&gt; 的 class，必须写 &lt;code&gt;render()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;2. 状态管理&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;函数组件&lt;/strong&gt;：&lt;code&gt;useState&lt;/code&gt; / &lt;code&gt;useReducer&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;类组件&lt;/strong&gt;：&lt;code&gt;this.state&lt;/code&gt; / &lt;code&gt;this.setState&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;3. 副作用/生命周期&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;函数组件&lt;/strong&gt;：&lt;code&gt;useEffect&lt;/code&gt; 统一管理&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;类组件&lt;/strong&gt;：&lt;code&gt;componentDidMount&lt;/code&gt; / &lt;code&gt;update&lt;/code&gt; / &lt;code&gt;unmount&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4. this 指向&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;函数组件&lt;/strong&gt;：&lt;strong&gt;没有 this&lt;/strong&gt;，完全不用管&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;类组件&lt;/strong&gt;：必须处理 this 绑定，容易出 bug&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;5. 逻辑复用&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;函数组件&lt;/strong&gt;：&lt;strong&gt;自定义 Hooks&lt;/strong&gt;，完美复用&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;类组件&lt;/strong&gt;：高阶组件、render-props，嵌套复杂&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;6. 性能 &amp;#x26; 未来&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;函数组件&lt;/strong&gt;：轻量、易编译、React 未来主推&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;类组件&lt;/strong&gt;：相对笨重，未来会逐步减少使用&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h1&gt;二、最直观代码对比&lt;/h1&gt;
&lt;h2&gt;函数组件（简洁）&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;function App() {
  const [count, setCount] = useState(0);

  useEffect(() =&gt; {
    // 逻辑
  }, []);

  return &amp;#x3C;div&gt;{count}&amp;#x3C;/div&gt;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;类组件（繁琐）&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;class App extends React.Component {
  constructor() {
    super();
    this.state = { count: 0 };
  }

  componentDidMount() {}
  componentDidUpdate() {}
  componentWillUnmount() {}

  render() {
    return &amp;#x3C;div&gt;{this.state.count}&amp;#x3C;/div&gt;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h1&gt;三、满分总结&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;函数组件是函数，类组件是 class&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;函数组件用 Hooks 管理状态，类组件用 this.state&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;函数组件无 this，类组件必须处理 this 指向&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;函数组件逻辑复用靠自定义 Hooks，类组件靠高阶组件&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;函数组件代码更简洁、性能更好，是 React 官方未来标准&lt;/strong&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h3&gt;一句话记住&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;函数组件 = 简洁 + Hooks + 无this + 未来主流
类组件 = 繁琐 + 生命周期 + this + 逐步淘汰&lt;/strong&gt;&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>ref 和 reactive 的区别？什么时候用哪个？</title><link>https://linme.cn/blog/%E5%89%8D%E7%AB%AF/vue/ref-%E5%92%8C-reactive-%E7%9A%84%E5%8C%BA%E5%88%AB%E4%BB%80%E4%B9%88%E6%97%B6%E5%80%99%E7%94%A8%E5%93%AA%E4%B8%AA</link><guid isPermaLink="true">https://linme.cn/blog/%E5%89%8D%E7%AB%AF/vue/ref-%E5%92%8C-reactive-%E7%9A%84%E5%8C%BA%E5%88%AB%E4%BB%80%E4%B9%88%E6%97%B6%E5%80%99%E7%94%A8%E5%93%AA%E4%B8%AA</guid><description>ref vs reactive</description><pubDate>Tue, 20 Jan 2026 16:40:43 GMT</pubDate><content:encoded>&lt;h2&gt;ref vs reactive&lt;/h2&gt;
&lt;p&gt;| | &lt;strong&gt;ref&lt;/strong&gt; | &lt;strong&gt;reactive&lt;/strong&gt; |
|:---|:---|:---|
| &lt;strong&gt;数据类型&lt;/strong&gt; | 任意（推荐基础类型） | 仅对象/数组 |
| &lt;strong&gt;访问方式&lt;/strong&gt; | &lt;code&gt;.value&lt;/code&gt; | 直接访问属性 |
| &lt;strong&gt;解构/展开&lt;/strong&gt; | 保持响应式（需 &lt;code&gt;.value&lt;/code&gt;） | 丢失响应式 |
| &lt;strong&gt;适用场景&lt;/strong&gt; | 单个值、原始类型、需要替换整个对象 | 复杂对象、表单数据 |&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;代码对比&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// ref: 包装成对象，通过 .value 读写
const count = ref(0);
console.log(count.value);  // 读取
count.value++;             // 修改

const user = ref({ name: &apos;Tom&apos; });
user.value.name = &apos;Jerry&apos;;  // 修改属性
user.value = { name: &apos;Bob&apos; }; // 替换整个对象 ✅

// reactive: 代理对象，直接访问
const state = reactive({ count: 0, name: &apos;Tom&apos; });
console.log(state.count);  // 直接读
state.count++;             // 直接改

// 不能替换整个对象
state = { count: 1 };  // ❌ 报错
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;关键陷阱：解构丢失响应式&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// reactive 解构 = 响应式丢失
const state = reactive({ x: 1, y: 2 });
const { x, y } = state;  // x, y 变成普通数字

// ref 解构 .value 也丢失
const pos = ref({ x: 1, y: 2 });
const { x, y } = pos.value;  // 同样丢失

// ✅ 解决方案：toRefs
import { toRefs } from &apos;vue&apos;;
const { x, y } = toRefs(reactive({ x: 1, y: 2 }));
// x, y 是 ref，保持响应式
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;选择指南&lt;/h2&gt;
&lt;p&gt;| 场景 | 推荐 | 原因 |
|:---|:---|:---|
| 数字、字符串、布尔 | &lt;code&gt;ref&lt;/code&gt; | 语义清晰 |
| 对象需要整体替换 | &lt;code&gt;ref&lt;/code&gt; | &lt;code&gt;user.value = newUser&lt;/code&gt; |
| 复杂对象、嵌套数据 | &lt;code&gt;reactive&lt;/code&gt; | 代码简洁，不用写 &lt;code&gt;.value&lt;/code&gt; |
| 表单数据 | &lt;code&gt;reactive&lt;/code&gt; | 字段多，直接访问方便 |
| 从函数返回响应式数据 | &lt;code&gt;ref&lt;/code&gt; | 解构安全 |&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;一句话&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;简单值用 &lt;code&gt;ref&lt;/code&gt;（记得 &lt;code&gt;.value&lt;/code&gt;），复杂对象用 &lt;code&gt;reactive&lt;/code&gt;（别解构）。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>db9.ai</title><link>https://linme.cn/blog/ai/%E7%8B%AC%E7%AB%8B%E5%BC%80%E5%8F%91/db9ai</link><guid isPermaLink="true">https://linme.cn/blog/ai/%E7%8B%AC%E7%AB%8B%E5%BC%80%E5%8F%91/db9ai</guid><description>dbb.ai 是什么？</description><pubDate>Mon, 19 Jan 2026 17:11:57 GMT</pubDate><content:encoded>&lt;h2&gt;dbb.ai 是什么？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;把本地 SQLite 数据库变成&lt;strong&gt;云端 API 服务&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2&gt;一句话解释&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;不用装 MySQL/Postgres，直接用 SQLite 文件，但通过网址访问&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;传统: 本地 app → 读写 local.db 文件

dbb.ai: 你的代码 → HTTP 请求 → 云端 SQLite → 返回 JSON
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;代码对比&lt;/h2&gt;
&lt;h3&gt;传统 SQLite（本地）&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// 只能本机用，无法多人同时访问
const sqlite3 = require(&apos;sqlite3&apos;);
const db = new sqlite3.Database(&apos;./local.db&apos;);

db.get(&apos;SELECT * FROM users&apos;, (err, row) =&gt; {
  console.log(row);
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;dbb.ai（云端）&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// 任何设备、任何语言都能访问
const db = createClient({
  url: &apos;https://xxx.dbb.ai&apos;,
  token: &apos;你的密钥&apos;
});

// 一样的 SQL，返回 Promise
const { rows } = await db.execute(&apos;SELECT * FROM users&apos;);
// rows = [{id: 1, name: &apos;Tom&apos;}, ...]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;解决什么问题？&lt;/h2&gt;
&lt;p&gt;| 场景 | 方案 |
|:---|:---|
| 快速搭个后端 | 不用买服务器，dbb.ai 直接当数据库 |
| 小程序/APP | 前端直接调 API，不用写后端代码 |
| 边缘函数 (Worker) | SQLite 轻量，冷启动快 |
| 原型开发 | 5 分钟上线，按量付费 |&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;实际例子：留言板&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// Cloudflare Worker + dbb.ai = 完整后端
export default {
  async fetch(request) {
    const db = createClient({ url, token });
    
    // GET /messages → 查留言
    if (request.method === &apos;GET&apos;) {
      const { rows } = await db.execute(
        &apos;SELECT * FROM messages ORDER BY time DESC&apos;
      );
      return Response.json(rows);
    }
    
    // POST /messages → 写留言
    const { text } = await request.json();
    await db.execute(
      &apos;INSERT INTO messages (text, time) VALUES (?, ?)&apos;,
      [text, Date.now()]
    );
    return Response.json({ ok: true });
  }
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;结果&lt;/strong&gt;：没买服务器，没配数据库，一个 Worker 文件搞定。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;核心优势&lt;/h2&gt;
&lt;p&gt;| 对比 | 结果 |
|:---|:---|
| vs MySQL/Postgres | 零配置，按请求付费，不是按实例 |
| vs Firebase | 标准 SQL，不用学新语法 |
| vs 自己搭 SQLite | 自动备份、多并发、全球访问 |&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;dbb.ai = SQLite 文件 + HTTP 接口 = 最简单的云端数据库&lt;/strong&gt;&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>Resend API</title><link>https://linme.cn/blog/ai/%E7%8B%AC%E7%AB%8B%E5%BC%80%E5%8F%91/resend-api</link><guid isPermaLink="true">https://linme.cn/blog/ai/%E7%8B%AC%E7%AB%8B%E5%BC%80%E5%8F%91/resend-api</guid><description>Resend API</description><pubDate>Mon, 19 Jan 2026 17:09:06 GMT</pubDate><content:encoded>&lt;h2&gt;Resend API&lt;/h2&gt;
&lt;p&gt;开发者友好的邮件发送服务，简洁 API + 高送达率。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;核心特性&lt;/h2&gt;
&lt;p&gt;| 特性 | 说明 |
|:---|:---|
| &lt;strong&gt;极简 API&lt;/strong&gt; | 一行代码发邮件 |
| &lt;strong&gt;React Email&lt;/strong&gt; | JSX 编写邮件模板 |
| &lt;strong&gt;高送达率&lt;/strong&gt; | 自动 DKIM/SPF/DMARC |
| &lt;strong&gt;免费额度&lt;/strong&gt; | 3,000 封/月 |&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;快速开始&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npm install resend
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;import { Resend } from &apos;resend&apos;;

const resend = new Resend(&apos;re_xxxxxxxx&apos;);

// 发送纯文本
await resend.emails.send({
  from: &apos;onboarding@yourdomain.com&apos;,
  to: &apos;user@example.com&apos;,
  subject: &apos;Hello&apos;,
  text: &apos;欢迎！&apos;,
});

// 发送 HTML
await resend.emails.send({
  from: &apos;noreply@yourdomain.com&apos;,
  to: [&apos;user1@a.com&apos;, &apos;user2@b.com&apos;],
  subject: &apos;订单确认&apos;,
  html: &apos;&amp;#x3C;h1&gt;感谢您的订单&amp;#x3C;/h1&gt;&apos;,
});
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;React Email（推荐）&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npm install @react-email/components
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;// emails/Welcome.tsx
import { Html, Button, Text } from &apos;@react-email/components&apos;;

export default function Welcome({ name, url }) {
  return (
    &amp;#x3C;Html&gt;
      &amp;#x3C;Text&gt;Hi {name},&amp;#x3C;/Text&gt;
      &amp;#x3C;Button href={url}&gt;确认邮箱&amp;#x3C;/Button&gt;
    &amp;#x3C;/Html&gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// 发送 JSX 邮件
import Welcome from &apos;./emails/Welcome&apos;;

await resend.emails.send({
  from: &apos;team@yourdomain.com&apos;,
  to: &apos;user@example.com&apos;,
  subject: &apos;欢迎加入&apos;,
  react: &amp;#x3C;Welcome name=&quot;John&quot; url=&quot;https://verify.com&quot; /&gt;,
});
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;批量发送&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// 批量 + 延迟
await resend.batch.send([
  { from, to: &apos;a@a.com&apos;, subject, html },
  { from, to: &apos;b@b.com&apos;, subject, html },
  { from, to: &apos;c@c.com&apos;, subject, html },
]);
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;与 Cloudflare Worker 结合&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;export default {
  async fetch(request, env) {
    const resend = new Resend(env.RESEND_API_KEY);
    
    await resend.emails.send({
      from: &apos;alert@yourdomain.com&apos;,
      to: &apos;admin@example.com&apos;,
      subject: &apos;服务器告警&apos;,
      text: await request.text(),
    });
    
    return new Response(&apos;Sent&apos;);
  }
};
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Resend = 极简代码发邮件 + React JSX 写模板，3分钟集成，3千封免费。&lt;/strong&gt;&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>Cloudflare Email Routing + Worker</title><link>https://linme.cn/blog/ai/%E7%8B%AC%E7%AB%8B%E5%BC%80%E5%8F%91/cloudflare-email-routing--worker</link><guid isPermaLink="true">https://linme.cn/blog/ai/%E7%8B%AC%E7%AB%8B%E5%BC%80%E5%8F%91/cloudflare-email-routing--worker</guid><description>Cloudflare Email Routing + Worker</description><pubDate>Mon, 19 Jan 2026 17:07:59 GMT</pubDate><content:encoded>&lt;h2&gt;Cloudflare Email Routing + Worker&lt;/h2&gt;
&lt;hr&gt;
&lt;h2&gt;架构&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;收到邮件 → Email Routing → 触发 Worker → 自定义处理
                ↓
           转发/丢弃/回复/存储/调用API
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;1. Email Routing 配置&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;Cloudflare Dashboard → Email → Email Routing
    ↓
Catch-all 地址: *@yourdomain.com → 转发到 Worker
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;2. Worker 接收邮件&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// worker.js
export default {
  async email(message, env, ctx) {
    // message: 邮件对象
    const {
      from,      // 发件人
      to,        // 收件人
      headers,   // 原始头
      raw,       // 原始内容
      rawSize,   // 大小
    } = message;

    // 读取内容
    const text = await message.text();
    const html = await message.html();

    // 处理逻辑
    if (text.includes(&apos;验证码&apos;)) {
      await env.DB.prepare(&apos;INSERT INTO codes (email, code) VALUES (?, ?)&apos;)
        .bind(from, extractCode(text)).run();
    }

    // 转发到 Gmail
    await message.forward(&apos;backup@gmail.com&apos;);
    
    // 或回复
    await message.reply({
      from: &apos;bot@yourdomain.com&apos;,
      subject: &apos;Re: &apos; + message.headers.get(&apos;subject&apos;),
      text: &apos;收到，处理中...&apos;,
    });
  }
};
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;3. wrangler.toml 配置&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-toml&quot;&gt;name = &quot;email-worker&quot;
main = &quot;worker.js&quot;

[[email]]
name = &quot;catch-all&quot;
destination = &quot;worker&quot;

# 绑定存储
[[d1_databases]]
binding = &quot;DB&quot;
database_name = &quot;emails&quot;
database_id = &quot;xxx&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;典型场景&lt;/h2&gt;
&lt;p&gt;| 场景 | 代码 |
|:---|:---|
| 自动回复 | &lt;code&gt;message.reply({...})&lt;/code&gt; |
| 过滤垃圾 | &lt;code&gt;if (spamCheck(raw)) message.setReject(&apos;Spam&apos;)&lt;/code&gt; |
| 提取数据 | &lt;code&gt;await message.text()&lt;/code&gt; 正则匹配 |
| 存储归档 | &lt;code&gt;await env.R2.put(key, raw)&lt;/code&gt; |
| 触发 webhook | &lt;code&gt;fetch(&apos;https://api.com/notify&apos;, {body: json})&lt;/code&gt; |&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Email Routing 收邮件 → Worker 写代码处理 → 转发/回复/存存储/调API，无服务器邮件自动化。&lt;/strong&gt;&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>raise</title><link>https://linme.cn/blog/%E8%AE%A1%E7%AE%97%E6%9C%BA/python/raise</link><guid isPermaLink="true">https://linme.cn/blog/%E8%AE%A1%E7%AE%97%E6%9C%BA/python/raise</guid><description>的本质</description><pubDate>Fri, 16 Jan 2026 14:38:26 GMT</pubDate><content:encoded>&lt;h2&gt;&lt;code&gt;raise&lt;/code&gt; 的本质&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;raise = 触发异常 + 中断当前执行流 + 向上层传递错误
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;基础语法&lt;/h2&gt;
&lt;h3&gt;1. 抛出异常实例（最常用）&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;raise HTTPException(status_code=404, detail=&quot;Not found&quot;)
#     └───────────┘  └─────────────────────────────┘
#       异常类           构造函数的参数
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. 抛出异常类（自动实例化）&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;raise ValueError          # 等价于 raise ValueError()
raise ValueError(&quot;msg&quot;)   # 带消息的实例
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. 重新抛出当前异常（在 except 块中）&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;try:
    risky()
except:
    print(&quot;记录日志&quot;)
    raise   # ← 不加参数，把捕获的异常继续向上抛
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;执行流程：程序如何&quot;炸&quot;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;正常执行流 ─────────────────────────►
              │
              ▼
         遇到 raise
              │
              ▼
    ┌─────────────────┐
    │  创建异常对象      │
    │  携带错误信息      │
    └─────────────────┘
              │
              ▼
    ┌─────────────────┐
    │  中断当前函数      │  ◄── 后面代码不执行！
    │  开始向上层逃逸    │
    └─────────────────┘
              │
              ▼
    每层检查: 有 try-except? ──► 有 → 捕获处理
              │                    │
              无                    ▼
              │              继续向上层逃逸
              ▼
         到达最顶层
              │
              ▼
         程序崩溃/500错误
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;代码示例：层层逃逸&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# 第3层：最底层，抛出异常
def get_item(item_id):
    if item_id &gt; 10:
        raise HTTPException(status_code=404, detail=&quot;Not found&quot;)
    return item_id

# 第2层：中间层，继续抛（或处理）
def process(item_id):
    result = get_item(item_id)  # ← 这里可能收到异常
    return result * 2

# 第1层：最上层，最终处理
@app.get(&quot;/items/{item_id}&quot;)
async def read_item(item_id: int):
    try:
        value = process(item_id)   # ← 异常向上传到这儿
        return {&quot;value&quot;: value}
    except HTTPException:
        raise                      # ← 再抛给 FastAPI 处理
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;调用 &lt;code&gt;read_item(99)&lt;/code&gt; 的执行栈：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;get_item(99) 中 raise HTTPException
        │
        ▼ 向上逃逸
process(99) 的 get_item(item_id) 调用点
        │
        ▼ 继续向上
read_item(99) 的 process(item_id) 调用点
        │
        ▼ 被 try-except 捕获
except HTTPException 捕获到
        │
        ▼ 重新 raise
FastAPI 异常处理器捕获 → 返回 404 JSON
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;与其他语言对比&lt;/h2&gt;
&lt;p&gt;| 语言 | 语法 | 特点 |
|------|------|------|
| Python | &lt;code&gt;raise ValueError(&quot;msg&quot;)&lt;/code&gt; | 必须抛异常&lt;strong&gt;对象&lt;/strong&gt;或&lt;strong&gt;类&lt;/strong&gt; |
| Java | &lt;code&gt;throw new Exception(&quot;msg&quot;)&lt;/code&gt; | 必须抛&lt;strong&gt;对象&lt;/strong&gt; |
| JavaScript | &lt;code&gt;throw &quot;msg&quot;&lt;/code&gt; / &lt;code&gt;throw new Error()&lt;/code&gt; | 可抛&lt;strong&gt;任何值&lt;/strong&gt; |
| Go | &lt;code&gt;return err&lt;/code&gt; | 无 raise，显式返回错误 |&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;高级用法&lt;/h2&gt;
&lt;h3&gt;异常链（保留原始错误）&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;try:
    int(&quot;not a number&quot;)
except ValueError as e:
    raise HTTPException(400, &quot;Invalid ID&quot;) from e
#     └────────────────────────────────────────┘
#              新异常 ← 原始异常
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;效果：&lt;/strong&gt; 日志显示完整链条：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTPException: Invalid ID
caused by ValueError: invalid literal for int()
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;自定义异常 + raise&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;class BusinessError(Exception):
    def __init__(self, code, message):
        self.code = code
        self.message = message

# 使用
raise BusinessError(1001, &quot;库存不足&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;关键记忆点&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;raise = 扔出一个&quot;炸弹&quot;
        │
        ├── 立即炸停当前函数
        │
        ├── 携带错误信息向上飞
        │
        └── 直到被 try-except 接住，或炸毁程序
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;一句话总结&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;raise&lt;/code&gt; 是 Python 的错误信号弹，触发后立即中断当前执行，携带错误信息向上层传递，直到被捕获处理或导致程序终止。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>yield</title><link>https://linme.cn/blog/%E8%AE%A1%E7%AE%97%E6%9C%BA/python/yield</link><guid isPermaLink="true">https://linme.cn/blog/%E8%AE%A1%E7%AE%97%E6%9C%BA/python/yield</guid><description>的核心作用： 暂停与恢复</description><pubDate>Mon, 12 Jan 2026 14:19:41 GMT</pubDate><content:encoded>&lt;h2&gt;&lt;code&gt;yield&lt;/code&gt; 的核心作用：&lt;strong&gt;暂停与恢复&lt;/strong&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;普通 return: 函数执行 → 返回值 → 函数结束（内存释放）
yield:       函数执行 → 产出值 → 暂停等待 → 被唤醒后继续执行
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;具体对比&lt;/h2&gt;
&lt;h3&gt;❌ 如果用 &lt;code&gt;return&lt;/code&gt;（错误）&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;def get_db():
    db = &quot;数据库连接&quot;
    return db           # ← 函数到这里就结束了！
    # 下面这行永远不会执行
    db = &quot;关闭连接&quot;     # ❌ 死代码，资源无法释放
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;结果：&lt;/strong&gt; 数据库连接永远无法关闭，造成&lt;strong&gt;连接泄漏&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;✅ 用 &lt;code&gt;yield&lt;/code&gt;（正确）&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;def get_db():
    db = &quot;数据库连接&quot;
    try:
        yield db        # ← 暂停！产出值，但函数不结束
    finally:
        db = &quot;关闭连接&quot; # ← 路由结束后，从这里继续执行
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;执行流程可视化&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;时间线 ─────────────────────────────────────────►

get_db() 开始
    │
    ▼
db = &quot;数据库连接&quot;  ◄── 创建资源
    │
    ▼
yield db           ◄── 【暂停点】产出值给路由函数
    │                  │
    │                  ▼
    │            read_items(db=...) 执行中
    │                  │
    │                  ▼
    │            路由函数完成
    │
    ▼ 【恢复执行】
finally:
    db = &quot;关闭连接&quot;  ◄── 清理资源（一定执行）
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;关键特性：上下文保持&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;def get_db():
    db = create_expensive_connection()  # 第1步：创建
    print(&quot;连接已创建&quot;)
    
    yield db                            # 第2步：交出控制权（暂停）
    
    # ↓↓↓ 路由结束后，从这里继续 ↓↓↓
    print(&quot;准备清理&quot;)
    db.close()                          # 第3步：清理
    print(&quot;连接已关闭&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;输出顺序：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;连接已创建      ← yield 之前
[路由函数执行中]  ← yield 暂停期间
准备清理        ← 路由结束后恢复
连接已关闭      ← 最终清理
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;类比理解&lt;/h2&gt;
&lt;p&gt;| 类比 | 解释 |
|------|------|
| &lt;strong&gt;游戏存档点&lt;/strong&gt; | &lt;code&gt;yield&lt;/code&gt; = 存档，下次从存档点继续，不是从头开始 |
| &lt;strong&gt;租借物品&lt;/strong&gt; | 借出（yield）→ 对方使用 → 归还后你做检查（finally）|
| &lt;strong&gt;协程/生成器&lt;/strong&gt; | Python 生成器的基础机制，支持双向通信 |&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;配合 &lt;code&gt;try...finally&lt;/code&gt; 的威力&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;def get_db():
    db = connect()
    try:
        yield db
        # 如果路由函数正常完成，执行到这里
    except Exception:
        # 如果路由函数抛出异常，也能捕获
        raise
    finally:
        db.close()  # ✅ 无论成功/失败，100%执行
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;这是 Python 中资源管理的最佳实践模式&lt;/strong&gt;，比 &lt;code&gt;__enter__/__exit__&lt;/code&gt; 上下文管理器更简洁。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;一句话总结&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;yield&lt;/code&gt; 让函数变成&quot;可暂停的&quot;，使得 FastAPI 能在请求处理前后自动执行 setup/teardown 逻辑，实现声明式的资源生命周期管理。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>Vue 2 和 Vue 3 的核心区别</title><link>https://linme.cn/blog/qianduan/vue/vue-2-%E5%92%8C-vue-3-%E7%9A%84%E6%A0%B8%E5%BF%83%E5%8C%BA%E5%88%AB</link><guid isPermaLink="true">https://linme.cn/blog/qianduan/vue/vue-2-%E5%92%8C-vue-3-%E7%9A%84%E6%A0%B8%E5%BF%83%E5%8C%BA%E5%88%AB</guid><description>Vue 2 vs Vue 3 核心区别</description><pubDate>Thu, 01 Jan 2026 16:46:12 GMT</pubDate><content:encoded>&lt;h2&gt;Vue 2 vs Vue 3 核心区别&lt;/h2&gt;
&lt;p&gt;| | &lt;strong&gt;Vue 2&lt;/strong&gt; | &lt;strong&gt;Vue 3&lt;/strong&gt; |
|:---|:---|:---|
| &lt;strong&gt;响应式&lt;/strong&gt; | &lt;code&gt;Object.defineProperty&lt;/code&gt; | &lt;code&gt;Proxy&lt;/code&gt; |
| &lt;strong&gt;新增属性&lt;/strong&gt; | 需 &lt;code&gt;Vue.set&lt;/code&gt; | 自动响应 |
| &lt;strong&gt;数组索引&lt;/strong&gt; | 检测不到 | 原生支持 |
| &lt;strong&gt;API 风格&lt;/strong&gt; | Options API | Options + &lt;strong&gt;Composition API&lt;/strong&gt; |
| &lt;strong&gt;逻辑复用&lt;/strong&gt; | Mixins（易冲突） | &lt;strong&gt;Composables&lt;/strong&gt;（清晰） |
| &lt;strong&gt;TypeScript&lt;/strong&gt; | 支持差 | 原生支持 |
| &lt;strong&gt;性能&lt;/strong&gt; | 初始化递归遍历 | 懒代理，更快 |
| &lt;strong&gt;Tree-shaking&lt;/strong&gt; | 差 | 更好（按需编译）|
| &lt;strong&gt;多根节点&lt;/strong&gt; | ❌ 单根 | ✅ 多根 &lt;code&gt;&amp;#x3C;template&gt;&lt;/code&gt; |
| &lt;strong&gt;Teleport&lt;/strong&gt; | ❌ | ✅ |
| &lt;strong&gt;Suspense&lt;/strong&gt; | ❌ | ✅ |&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;代码对比&lt;/h2&gt;
&lt;h3&gt;响应式&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// Vue 2
Vue.set(obj, &apos;newKey&apos;, value);  // 新增属性需特殊方法
arr[0] = 1;  // 检测不到

// Vue 3
obj.newKey = value;  // 直接赋值，自动响应
arr[0] = 1;  // 正常检测
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;API 风格&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// Vue 2: Options API
export default {
  data() { return { count: 0 }; },
  methods: { increment() { this.count++; } },
  computed: { double() { return this.count * 2; } }
};

// Vue 3: Composition API
import { ref, computed } from &apos;vue&apos;;

export default {
  setup() {
    const count = ref(0);
    const double = computed(() =&gt; count.value * 2);
    const increment = () =&gt; count.value++;
    
    return { count, double, increment };
  }
};
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;一句话&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Vue 3 = Proxy 响应式 + Composition API + 更好的 TS 支持 + 新特性（Teleport/Suspense）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>React.memo vs useMemo 区别</title><link>https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/reactmemo-vs-usememo-%E5%8C%BA%E5%88%AB</link><guid isPermaLink="true">https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/reactmemo-vs-usememo-%E5%8C%BA%E5%88%AB</guid><description>一句话总结： React.memo 是缓存「整个组件」，useMemo 是缓存「组件内的计算值/函数」 ，一个管组件，一个管数据，用途完全不同。</description><pubDate>Thu, 04 Dec 2025 23:59:17 GMT</pubDate><content:encoded>&lt;p&gt;一句话总结：&lt;strong&gt;React.memo 是缓存「整个组件」，useMemo 是缓存「组件内的计算值/函数」&lt;/strong&gt;，一个管组件，一个管数据，用途完全不同。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;1. 核心定义与本质&lt;/h2&gt;
&lt;h3&gt;🧩 React.memo&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;类型&lt;/strong&gt;：&lt;strong&gt;高阶组件 (HOC)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;作用&lt;/strong&gt;：&lt;strong&gt;缓存组件本身&lt;/strong&gt;，防止组件&lt;strong&gt;不必要的重新渲染&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;使用场景&lt;/strong&gt;：给&lt;strong&gt;函数组件&lt;/strong&gt;做性能优化，避免父组件渲染时子组件无脑跟着重渲染&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;缓存目标&lt;/strong&gt;：&lt;strong&gt;组件的渲染结果（UI）&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;🧮 useMemo&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;类型&lt;/strong&gt;：&lt;strong&gt;React Hook&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;作用&lt;/strong&gt;：&lt;strong&gt;缓存「昂贵计算的结果」&lt;/strong&gt;，避免每次渲染都重复计算&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;使用场景&lt;/strong&gt;：组件内&lt;strong&gt;耗时的计算逻辑&lt;/strong&gt;、需要稳定引用的对象/数组&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;缓存目标&lt;/strong&gt;：&lt;strong&gt;变量/值&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;2. 语法对比&lt;/h2&gt;
&lt;h3&gt;React.memo（包裹整个组件）&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;// 缓存整个子组件，props 不变就不重新渲染
const Child = React.memo(function Child({ name }) {
  return &amp;#x3C;div&gt;{name}&amp;#x3C;/div&gt;;
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;useMemo（组件内使用，缓存值）&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;function Parent() {
  const [count, setCount] = useState(0);

  // 缓存昂贵计算结果，依赖项不变就不重新计算
  const expensiveValue = useMemo(() =&gt; {
    console.log(&quot;只在依赖变化时执行&quot;);
    return count * 2; // 模拟耗时计算
  }, [count]); // 依赖数组

  return &amp;#x3C;div&gt;{expensiveValue}&amp;#x3C;/div&gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;3. 关键区别对照表&lt;/h2&gt;
&lt;p&gt;| 特性                | React.memo                          | useMemo                              |
| :------------------ | :---------------------------------- | :----------------------------------- |
| &lt;strong&gt;是什么&lt;/strong&gt;          | 高阶组件 (HOC)                      | Hook                                 |
| &lt;strong&gt;缓存什么&lt;/strong&gt;        | 整个组件的渲染结果                  | 组件内的计算值/变量                  |
| &lt;strong&gt;解决什么问题&lt;/strong&gt;    | 防止子组件&lt;strong&gt;不必要重渲染&lt;/strong&gt;          | 防止组件内&lt;strong&gt;重复昂贵计算&lt;/strong&gt;           |
| &lt;strong&gt;使用位置&lt;/strong&gt;        | 包裹&lt;strong&gt;函数组件&lt;/strong&gt;                    | 写在&lt;strong&gt;组件内部&lt;/strong&gt;                     |
| &lt;strong&gt;依赖控制&lt;/strong&gt;        | 自动浅比较 props                    | 手动传入依赖数组                     |
| &lt;strong&gt;返回值&lt;/strong&gt;          | 一个缓存后的新组件                  | 一个缓存后的计算值                   |&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;4. 最直观的使用场景&lt;/h2&gt;
&lt;h3&gt;✅ 用 React.memo 的场景&lt;/h3&gt;
&lt;p&gt;子组件是&lt;strong&gt;纯展示组件&lt;/strong&gt;，props 不变就不需要重新渲染：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;// 父组件渲染时，Child 只要 props 不变就不重渲染
const Parent = () =&gt; {
  const [num, setNum] = useState(1);
  return (
    &amp;#x3C;&gt;
      &amp;#x3C;button onClick={() =&gt; setNum(num+1)}&gt;加一&amp;#x3C;/button&gt;
      {/* 子组件被 memo 缓存 */}
      &amp;#x3C;Child name=&quot;小明&quot; /&gt;
    &amp;#x3C;/&gt;
  );
};
// 包裹子组件
const Child = React.memo(({ name }) =&gt; {
  console.log(&quot;子组件渲染&quot;); // 只有 props 变才会打印
  return &amp;#x3C;div&gt;{name}&amp;#x3C;/div&gt;;
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;✅ 用 useMemo 的场景&lt;/h3&gt;
&lt;p&gt;组件内有&lt;strong&gt;耗时计算&lt;/strong&gt;，不想每次渲染都重新算：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;const List = ({ data }) =&gt; {
  // 过滤大量数据是耗时操作，用 useMemo 缓存结果
  const filteredList = useMemo(() =&gt; {
    return data.filter(item =&gt; item.value &gt; 100);
  }, [data]); // 仅 data 变化时重新过滤

  return &amp;#x3C;div&gt;{filteredList.map(item =&gt; &amp;#x3C;div key={item.id}&gt;{item.name}&amp;#x3C;/div&gt;)}&amp;#x3C;/div&gt;;
};
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;5. 重要注意事项&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;不要滥用&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;简单组件、轻量计算，用它们&lt;strong&gt;反而增加性能开销&lt;/strong&gt;（缓存本身有成本）&lt;/li&gt;
&lt;li&gt;只给&lt;strong&gt;频繁重渲染的子组件&lt;/strong&gt;用 React.memo&lt;/li&gt;
&lt;li&gt;只给&lt;strong&gt;耗时计算&lt;/strong&gt;用 useMemo&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;都是浅比较&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;React.memo 浅比较 props&lt;/li&gt;
&lt;li&gt;useMemo 浅比较依赖项&lt;/li&gt;
&lt;li&gt;传递对象/数组时，需要配合 useMemo/useCallback 保证引用不变&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;本质不同&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;React.memo = 组件级缓存&lt;/li&gt;
&lt;li&gt;useMemo = 数值级缓存&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;React.memo&lt;/strong&gt;：给&lt;strong&gt;组件&lt;/strong&gt;瘦身，防止子组件无效重渲染&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;useMemo&lt;/strong&gt;：给&lt;strong&gt;计算&lt;/strong&gt;瘦身，防止重复执行昂贵逻辑&lt;/li&gt;
&lt;li&gt;二者互补，不是二选一，可在项目中配合使用&lt;/li&gt;
&lt;/ol&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>useEffect 依赖数组判断机制</title><link>https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/useeffect-%E4%BE%9D%E8%B5%96%E6%95%B0%E7%BB%84%E5%88%A4%E6%96%AD%E6%9C%BA%E5%88%B6</link><guid isPermaLink="true">https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/useeffect-%E4%BE%9D%E8%B5%96%E6%95%B0%E7%BB%84%E5%88%A4%E6%96%AD%E6%9C%BA%E5%88%B6</guid><description>一句话核心结论</description><pubDate>Fri, 28 Nov 2025 13:40:25 GMT</pubDate><content:encoded>&lt;h2&gt;一句话核心结论&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;React 对依赖数组里的每一项，都做 「全等比较（===）」，只要有任意一项变了，effect 就重新执行。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;1. 底层判断规则&lt;/h2&gt;
&lt;p&gt;每次组件渲染，React 都会做这 3 步：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;记录&lt;strong&gt;上一次&lt;/strong&gt;的依赖数组 &lt;code&gt;[a, b, c]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;拿到&lt;strong&gt;本次&lt;/strong&gt;新的依赖数组 &lt;code&gt;[a, b, c]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;逐项进行 &lt;code&gt;===&lt;/code&gt; 比较&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;全部相等 → &lt;strong&gt;不执行&lt;/strong&gt; effect&lt;/li&gt;
&lt;li&gt;任意一个不等 → &lt;strong&gt;执行&lt;/strong&gt; effect&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;关键：是「全等比较」，不是「值相等」&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// 基本类型：值相同 → === 相等 → 判定不变
1 === 1 → true
&apos;abc&apos; === &apos;abc&apos; → true

// 引用类型：地址相同 → === 相等
// 地址不同 → 即使内容一样，也判定变化！
{} === {} → false
[] === [] → false
()=&gt;{} === ()=&gt;{} → false
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;2. 不同数据类型的判断结果&lt;/h2&gt;
&lt;h3&gt;① 基本类型（数字、字符串、布尔、null、undefined）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;直接比较值&lt;/strong&gt;，值不变 → 判定不变&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// 只会在 count 真正变化时执行
useEffect(() =&gt; {
  console.log(count);
}, [count]); 
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;② 引用类型（对象、数组、函数）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;比较内存地址&lt;/strong&gt;，&lt;strong&gt;地址变了 → 判定变化&lt;/strong&gt;
这是 90% 的 bug 来源！&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// 每次渲染都创建新对象 → 地址变 → effect 每次都执行！
useEffect(() =&gt; {
  console.log(&apos;我每次渲染都跑！&apos;);
}, [{ name: &apos;react&apos; }]); 

// 每次渲染都创建新数组 → effect 每次执行
useEffect(() =&gt; {
  console.log(&apos;我每次渲染都跑！&apos;);
}, [[1,2,3]]); 
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;3. 最容易踩坑的 3 个场景&lt;/h2&gt;
&lt;h3&gt;坑 1：直接在依赖里写对象/数组&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;function App() {
  const [count, setCount] = useState(0);

  // ❌ 错误：每次渲染都是新对象，effect 无限执行
  useEffect(() =&gt; {
    console.log(&apos;执行&apos;);
  }, [{ id: 1 }]);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;解决方案&lt;/strong&gt;：用 &lt;code&gt;useMemo&lt;/code&gt; 缓存对象/数组&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const obj = useMemo(() =&gt; ({ id: 1 }), []);
useEffect(() =&gt; {
  console.log(&apos;执行&apos;);
}, [obj]); // ✅ 地址不变
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;坑 2：依赖里写函数（每次渲染都是新函数）&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// ❌ 错误
useEffect(() =&gt; {
  fetchData();
}, [fetchData]); 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;解决方案&lt;/strong&gt;：用 &lt;code&gt;useCallback&lt;/code&gt; 缓存函数&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const fetchData = useCallback(() =&gt; { ... }, []);
useEffect(() =&gt; {
  fetchData();
}, [fetchData]); // ✅ 地址不变
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;坑 3：空依赖数组 &lt;code&gt;[]&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;所有项都不变 → 只在组件挂载执行一次，卸载清理一次&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;4. 完整执行流程图&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;组件初次渲染 → &lt;strong&gt;执行 effect&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;组件更新 → 生成&lt;strong&gt;新依赖数组&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;React &lt;strong&gt;逐项 &lt;code&gt;===&lt;/code&gt; 对比新旧依赖&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;全相等 → &lt;strong&gt;不执行&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;有一个不等 → &lt;strong&gt;先执行清理函数 → 再执行新 effect&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;useEffect 依赖判断用 &lt;strong&gt;&lt;code&gt;===&lt;/code&gt; 全等比较&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;基本类型比数值&lt;/strong&gt;，&lt;strong&gt;引用类型比内存地址&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;对象/数组/函数必须用 &lt;code&gt;useMemo / useCallback&lt;/code&gt; 缓存，否则会重复执行&lt;/li&gt;
&lt;li&gt;空依赖 &lt;code&gt;[]&lt;/code&gt; = 只执行一次&lt;/li&gt;
&lt;/ol&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>Fiber 架构工作原理</title><link>https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/fiber-%E6%9E%B6%E6%9E%84%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86</link><guid isPermaLink="true">https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/fiber-%E6%9E%B6%E6%9E%84%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86</guid><description>一句话总结：</description><pubDate>Sat, 22 Nov 2025 03:08:44 GMT</pubDate><content:encoded>&lt;p&gt;一句话总结：
&lt;strong&gt;Fiber 就是把原来一次性同步阻塞的渲染，改成可中断、可恢复、可调度的异步任务，让浏览器不卡顿。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;1. 为什么要有 Fiber？&lt;/h2&gt;
&lt;p&gt;React 16 之前叫 &lt;strong&gt;Stack Reconciler（栈协调器）&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;虚拟 DOM diff 是&lt;strong&gt;同步递归&lt;/strong&gt;执行的&lt;/li&gt;
&lt;li&gt;一旦开始，就&lt;strong&gt;必须执行完&lt;/strong&gt;，中途不能停&lt;/li&gt;
&lt;li&gt;计算量大时，JS 会&lt;strong&gt;阻塞浏览器渲染、交互&lt;/strong&gt;（掉帧、卡顿）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Fiber 要解决的核心问题：
&lt;strong&gt;让 React 的更新任务可以被打断、优先保证高优任务（点击、输入），再回头继续渲染。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;2. Fiber 核心概念&lt;/h2&gt;
&lt;h3&gt;① Fiber Node&lt;/h3&gt;
&lt;p&gt;每个 React 元素，都会对应一个 &lt;strong&gt;Fiber 节点&lt;/strong&gt;，它是一个普通 JS 对象，包含：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;type&lt;/code&gt;：组件类型&lt;/li&gt;
&lt;li&gt;&lt;code&gt;props&lt;/code&gt;：属性&lt;/li&gt;
&lt;li&gt;&lt;code&gt;child / sibling / return&lt;/code&gt;：构成链表树&lt;/li&gt;
&lt;li&gt;&lt;code&gt;alternate&lt;/code&gt;：新旧 Fiber 树的连接（双缓冲）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;effectTag&lt;/code&gt;：标记要做什么操作（新增、删除、更新）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;priority&lt;/code&gt;：任务优先级&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;② Fiber 树 = 链表结构&lt;/h3&gt;
&lt;p&gt;不再是递归树，而是&lt;strong&gt;单链表&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;child&lt;/code&gt;：第一个子节点&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sibling&lt;/code&gt;：兄弟节点&lt;/li&gt;
&lt;li&gt;&lt;code&gt;return&lt;/code&gt;：父节点&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这样遍历不需要递归栈，可以&lt;strong&gt;随时暂停/继续&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;3. Fiber 两大阶段（最关键）&lt;/h2&gt;
&lt;p&gt;Fiber 把整个更新流程切成&lt;strong&gt;两阶段&lt;/strong&gt;：&lt;/p&gt;
&lt;h3&gt;阶段一：Reconciliation / Render 阶段（可中断）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;做 diff，生成 Fiber 树，标记副作用&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;遍历 Fiber 树&lt;/li&gt;
&lt;li&gt;对比新旧节点&lt;/li&gt;
&lt;li&gt;标记每个节点：增/删/改&lt;/li&gt;
&lt;li&gt;此阶段&lt;strong&gt;可以被高优任务打断&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;可能&lt;strong&gt;执行多次&lt;/strong&gt;，不操作真实 DOM&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;阶段二：Commit 阶段（不可中断）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;一次性把所有修改同步到真实 DOM&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;执行所有 effectTag&lt;/li&gt;
&lt;li&gt;操作 DOM&lt;/li&gt;
&lt;li&gt;执行生命周期 / useEffect&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;一旦开始必须执行完&lt;/strong&gt;，保证 DOM 一致性&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;4. 调度机制：Scheduler（调度器）&lt;/h2&gt;
&lt;p&gt;Fiber 配合调度器实现：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;给任务分&lt;strong&gt;优先级&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Immediate（最高，同步）&lt;/li&gt;
&lt;li&gt;UserBlocking（点击、输入）&lt;/li&gt;
&lt;li&gt;Normal（普通更新）&lt;/li&gt;
&lt;li&gt;Low&lt;/li&gt;
&lt;li&gt;Idle（最低）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;利用 &lt;strong&gt;requestIdleCallback / MessageChannel&lt;/strong&gt; 模拟时间切片&lt;/li&gt;
&lt;li&gt;每执行一小段任务，就&lt;strong&gt;让出主线程&lt;/strong&gt;给浏览器&lt;/li&gt;
&lt;li&gt;有空再回来继续执行&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一句话：
&lt;strong&gt;把一大坨计算，切成一小片一小片，浏览器有空就做，没空就先响应用户。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;5. 工作流程（极简版）&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;触发更新（setState、props 变化）&lt;/li&gt;
&lt;li&gt;Scheduler 分配优先级&lt;/li&gt;
&lt;li&gt;进入 Render 阶段：
&lt;ul&gt;
&lt;li&gt;从根节点开始遍历 Fiber 链表&lt;/li&gt;
&lt;li&gt;diff 标记更新&lt;/li&gt;
&lt;li&gt;时间片用完 → 暂停&lt;/li&gt;
&lt;li&gt;高优任务来了 → 打断，先处理高优&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Render 完成，得到&lt;strong&gt;副作用列表&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;进入 Commit 阶段：
&lt;ul&gt;
&lt;li&gt;一次性更新 DOM&lt;/li&gt;
&lt;li&gt;执行 useEffect、useLayoutEffect&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2&gt;6. 与老架构 Stack 的区别&lt;/h2&gt;
&lt;p&gt;| 特性 | Stack 架构 | Fiber 架构 |
|----|----|----|
| 执行方式 | 同步递归 | 异步可中断 |
| 能否暂停 | 不能 | 能 |
| 能否恢复 | 不能 | 能 |
| 优先级 | 无 | 支持优先级调度 |
| 主线程阻塞 | 严重 | 极小 |
| 遍历结构 | 树递归 | 链表循环 |&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;7. 一句话记住 Fiber&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Fiber = 链表结构 + 可中断 Render + 优先级调度 + 不可中断 Commit&lt;/strong&gt;
让 React 从“卡死式同步渲染”变成“流畅异步协作式渲染”。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>为什么 React 需要 Fiber 而 Vue 不需要？</title><link>https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/%E4%B8%BA%E4%BB%80%E4%B9%88-react-%E9%9C%80%E8%A6%81-fiber-%E8%80%8C-vue-%E4%B8%8D%E9%9C%80%E8%A6%81</link><guid isPermaLink="true">https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/%E4%B8%BA%E4%BB%80%E4%B9%88-react-%E9%9C%80%E8%A6%81-fiber-%E8%80%8C-vue-%E4%B8%8D%E9%9C%80%E8%A6%81</guid><description>一句话结论</description><pubDate>Sat, 08 Nov 2025 09:29:37 GMT</pubDate><content:encoded>&lt;h1&gt;一句话结论&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;不是 Vue 不需要，而是两者解决卡顿的思路完全不一样：
React 用 Fiber 做「异步可中断渲染」，
Vue 用「响应式精准追踪」做到根本不需要大规模 diff，自然不卡。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;1. 核心原因：两者更新机制天差地别&lt;/h1&gt;
&lt;h2&gt;React：粗放式更新 → 必须 Fiber&lt;/h2&gt;
&lt;p&gt;React 是&lt;strong&gt;组件级更新&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;setState 后，&lt;strong&gt;整个组件树从头开始重新渲染&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;要递归 diff 整棵虚拟 DOM 树&lt;/li&gt;
&lt;li&gt;节点一多，diff 计算量巨大 → &lt;strong&gt;主线程阻塞、页面卡顿&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以 React 必须搞 Fiber：
&lt;strong&gt;把大计算切碎、可中断、可调度，保证不卡死 UI。&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Vue：精准式更新 → 不需要大规模 diff&lt;/h2&gt;
&lt;p&gt;Vue 是&lt;strong&gt;响应式依赖追踪&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据变更时，Vue 精确知道&lt;strong&gt;哪个组件、哪个变量变了&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;只更新&lt;strong&gt;对应组件&lt;/strong&gt;，不扩散渲染&lt;/li&gt;
&lt;li&gt;diff 范围极小、计算极轻
→ &lt;strong&gt;计算量本来就小，根本不会阻塞主线程&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以 Vue &lt;strong&gt;天然不需要 Fiber 这种重型架构&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;2. 更本质的区别&lt;/h1&gt;
&lt;h2&gt;React&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;函数式思想：UI = f(state)&lt;/li&gt;
&lt;li&gt;状态变 → 重新跑函数 → 重新生成 VDOM&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;全量对比&lt;/strong&gt; → 计算量大
→ 必须 Fiber 来“异步分片”解决卡顿&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Vue&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;响应式思想：依赖收集&lt;/li&gt;
&lt;li&gt;状态变 → 通知&lt;strong&gt;精确的组件&lt;/strong&gt;更新&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;局部对比&lt;/strong&gt; → 计算量极小
→ 同步渲染完全足够，不卡&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h1&gt;3. 那 Vue 就完全没有类似机制吗？&lt;/h1&gt;
&lt;p&gt;有，但&lt;strong&gt;轻得多&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;Vue 3 引入了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Scheduler 调度队列&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;微任务批量更新&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;组件更新有优先级&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但它&lt;strong&gt;不是 Fiber&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;没有可中断渲染&lt;/li&gt;
&lt;li&gt;没有时间切片&lt;/li&gt;
&lt;li&gt;没有链表遍历结构&lt;/li&gt;
&lt;li&gt;没有双缓冲树&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因为&lt;strong&gt;根本用不上&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;4. 超精简总结&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;React 更新是粗放的&lt;/strong&gt;
setState → 整棵树重渲染、重 diff → 计算量大 → 必须用 Fiber 做&lt;strong&gt;异步可中断分片&lt;/strong&gt;，防止卡顿。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Vue 更新是精准的&lt;/strong&gt;
响应式依赖收集 → 只更新变化的组件 → diff 极轻 → 同步渲染足够流畅 → &lt;strong&gt;不需要 Fiber&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;不是 Vue 更高级，而是&lt;strong&gt;设计哲学不同&lt;/strong&gt;：
React 追求函数式简洁，代价是渲染量大，需要架构兜底；
Vue 用响应式换精准更新，代价是代理/依赖收集复杂，但运行时更快更轻。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>Vue3 响应式 vs Vue2</title><link>https://linme.cn/blog/%E5%89%8D%E7%AB%AF/vue/vue3-%E5%93%8D%E5%BA%94%E5%BC%8F-vs-vue2</link><guid isPermaLink="true">https://linme.cn/blog/%E5%89%8D%E7%AB%AF/vue/vue3-%E5%93%8D%E5%BA%94%E5%BC%8F-vs-vue2</guid><description>Vue3 vs Vue2 响应式核心差异</description><pubDate>Sat, 27 Sep 2025 04:33:53 GMT</pubDate><content:encoded>&lt;h2&gt;Vue3 vs Vue2 响应式核心差异&lt;/h2&gt;
&lt;p&gt;| 特性 | Vue2 | Vue3 |
|:---|:---|:---|
| &lt;strong&gt;实现方式&lt;/strong&gt; | &lt;code&gt;Object.defineProperty&lt;/code&gt; | &lt;code&gt;Proxy&lt;/code&gt; |
| &lt;strong&gt;拦截范围&lt;/strong&gt; | 已有属性 | 整个对象（含新增/删除） |
| &lt;strong&gt;数组支持&lt;/strong&gt; | 重写 7 个方法（push/pop等） | 原生支持索引和 length |
| &lt;strong&gt;Map/Set&lt;/strong&gt; | ❌ 不支持 | ✅ 原生支持 |
| &lt;strong&gt;性能&lt;/strong&gt; | 初始化递归遍历 | 懒代理（访问时才创建）|
| &lt;strong&gt;兼容性&lt;/strong&gt; | IE9+ | 现代浏览器（IE 不支持）|&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;关键代码对比&lt;/h2&gt;
&lt;h3&gt;Vue2：递归劫持&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// 初始化时遍历所有属性
function observe(obj) {
  Object.keys(obj).forEach(key =&gt; {
    defineReactive(obj, key, obj[key]);
    if (typeof obj[key] === &apos;object&apos;) {
      observe(obj[key]); // 递归
    }
  });
}

// 数组需特殊处理
const arrayMethods = [&apos;push&apos;, &apos;pop&apos;, &apos;splice&apos; /*...*/];
arrayMethods.forEach(method =&gt; {
  // 重写方法以触发更新
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;痛点&lt;/strong&gt;：新增属性需 &lt;code&gt;Vue.set&lt;/code&gt;，数组索引修改检测不到。&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Vue3：Proxy 懒代理&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function reactive(target) {
  return new Proxy(target, {
    get(target, key, receiver) {
      track(target, key);           // 依赖收集
      const result = Reflect.get(target, key, receiver);
      return isObject(result) 
        ? reactive(result)          // 懒递归：访问时才代理
        : result;
    },
    set(target, key, value, receiver) {
      const result = Reflect.set(target, key, value, receiver);
      trigger(target, key);         // 触发更新
      return result;
    }
    // 自动支持 delete、has、ownKeys 等
  });
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;优势&lt;/strong&gt;：新增/删除属性自动响应，数组原生支持。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>Vue3 不需要时间分片的原因</title><link>https://linme.cn/blog/%E5%89%8D%E7%AB%AF/vue/vue3-%E4%B8%8D%E9%9C%80%E8%A6%81%E6%97%B6%E9%97%B4%E5%88%86%E7%89%87%E7%9A%84%E5%8E%9F%E5%9B%A0</link><guid isPermaLink="true">https://linme.cn/blog/%E5%89%8D%E7%AB%AF/vue/vue3-%E4%B8%8D%E9%9C%80%E8%A6%81%E6%97%B6%E9%97%B4%E5%88%86%E7%89%87%E7%9A%84%E5%8E%9F%E5%9B%A0</guid><description>Vue3 不需要时间分片的原因</description><pubDate>Tue, 23 Sep 2025 15:18:25 GMT</pubDate><content:encoded>&lt;h2&gt;Vue3 不需要时间分片的原因&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// React：不知道谁变了，必须遍历整棵树
function App() {
  const [count, setCount] = useState(0);
  return (
    &amp;#x3C;div&gt;
      &amp;#x3C;A /&gt;      // 必须检查
      &amp;#x3C;B /&gt;      // 必须检查
      &amp;#x3C;C count={count} /&gt;  // 只有这里变
    &amp;#x3C;/div&gt;
  ); // 更新路径：App → A → B → C（全走一遍）
}

// Vue3：精确追踪，只更新用到的
&amp;#x3C;template&gt;
  &amp;#x3C;A /&gt;        &amp;#x3C;!-- 不更新 --&gt;
  &amp;#x3C;B /&gt;        &amp;#x3C;!-- 不更新 --&gt;
  &amp;#x3C;C :count=&quot;count&quot; /&gt;  &amp;#x3C;!-- 只有这里更新 --&gt;
&amp;#x3C;/template&gt;

// 响应式系统建立依赖图谱
count: [C组件]  // 只通知C
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;核心对比&lt;/h2&gt;
&lt;p&gt;| | React | Vue3 |
|:---|:---|:---|
| &lt;strong&gt;更新粒度&lt;/strong&gt; | 组件级（粗） | 依赖级（细） |
| &lt;strong&gt;遍历范围&lt;/strong&gt; | 整棵树 | 仅订阅组件 |
| &lt;strong&gt;时间分片&lt;/strong&gt; | 需要（遍历可能阻塞） | 不需要（路径极短） |&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Vue3 的异步批处理（足够用了）&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const state = reactive({ count: 0 });

state.count++;  // 加入队列
state.count++;  // 合并
state.count++;  // 合并

// 微任务阶段：只渲染一次
Promise.resolve().then(() =&gt; {
  // 批量更新 DOM
});
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;React 遍历成本高 → 需要中断&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Vue3 更新成本天然低 → 无需中断&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>Vue 有了响应式为何还要 Diff？</title><link>https://linme.cn/blog/%E5%89%8D%E7%AB%AF/vue/vue-%E6%9C%89%E4%BA%86%E5%93%8D%E5%BA%94%E5%BC%8F%E4%B8%BA%E4%BD%95%E8%BF%98%E8%A6%81-diff</link><guid isPermaLink="true">https://linme.cn/blog/%E5%89%8D%E7%AB%AF/vue/vue-%E6%9C%89%E4%BA%86%E5%93%8D%E5%BA%94%E5%BC%8F%E4%B8%BA%E4%BD%95%E8%BF%98%E8%A6%81-diff</guid><description>Vue 有响应式为何还要 Diff？</description><pubDate>Wed, 10 Sep 2025 21:06:13 GMT</pubDate><content:encoded>&lt;h2&gt;Vue 有响应式为何还要 Diff？&lt;/h2&gt;
&lt;p&gt;响应式知道&lt;strong&gt;哪个组件&lt;/strong&gt;要更新，Diff 决定&lt;strong&gt;怎么更新 DOM&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;两者职责&lt;/h2&gt;
&lt;p&gt;| | 作用 | 解决什么问题 |
|:---|:---|:---|
| &lt;strong&gt;响应式&lt;/strong&gt; | 追踪数据 → 定位组件 | 哪个组件需要更新 |
| &lt;strong&gt;Diff&lt;/strong&gt; | 对比 VDOM → 最小化 DOM 操作 | 如何高效更新该组件 |&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;代码示例&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// 响应式：知道 Child 组件要更新
const state = reactive({ list: [{ id: 1, text: &apos;a&apos; }] });

// 状态变化
state.list.push({ id: 2, text: &apos;b&apos; });  // 通知 Child 更新

// Child 渲染新 VDOM
// 旧: [li#a]  
// 新: [li#a, li#b]

// Diff：对比新旧 VDOM，只插入新 li，复用旧 li
// 而非清空整个 ul 重新创建
&lt;/code&gt;&lt;/pre&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>Teleport 与 Suspense</title><link>https://linme.cn/blog/%E5%89%8D%E7%AB%AF/vue/teleport-%E4%B8%8E-suspense</link><guid isPermaLink="true">https://linme.cn/blog/%E5%89%8D%E7%AB%AF/vue/teleport-%E4%B8%8E-suspense</guid><description>Teleport vs Suspense</description><pubDate>Wed, 27 Aug 2025 09:40:24 GMT</pubDate><content:encoded>&lt;h2&gt;Teleport vs Suspense&lt;/h2&gt;
&lt;p&gt;| | &lt;strong&gt;Teleport&lt;/strong&gt; | &lt;strong&gt;Suspense&lt;/strong&gt; |
|:---|:---|:---|
| &lt;strong&gt;作用&lt;/strong&gt; | 改变渲染位置（DOM 移动） | 处理异步依赖（加载状态） |
| &lt;strong&gt;解决&lt;/strong&gt; | 模态框/通知等脱离父组件层级 | 异步组件/数据加载的优雅降级 |
| &lt;strong&gt;状态&lt;/strong&gt; | 同步，立即渲染 | 异步，等待完成 |&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;代码对比&lt;/h2&gt;
&lt;h3&gt;Teleport：DOM 位置转移&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-vue&quot;&gt;&amp;#x3C;!-- 组件内声明，渲染到 body 下 --&gt;
&amp;#x3C;template&gt;
  &amp;#x3C;div class=&quot;parent&quot;&gt;
    &amp;#x3C;!-- 遮罩层逻辑在组件内，但 DOM 跑到 body 下 --&gt;
    &amp;#x3C;Teleport to=&quot;body&quot;&gt;
      &amp;#x3C;div class=&quot;modal&quot;&gt;弹窗内容&amp;#x3C;/div&gt;
    &amp;#x3C;/Teleport&gt;
  &amp;#x3C;/div&gt;
&amp;#x3C;/template&gt;

&amp;#x3C;!-- 结果 DOM --&gt;
&amp;#x3C;body&gt;
  &amp;#x3C;div id=&quot;app&quot;&gt;...&amp;#x3C;/div&gt;
  &amp;#x3C;div class=&quot;modal&quot;&gt;弹窗内容&amp;#x3C;/div&gt;  &amp;#x3C;!-- 在这里！ --&gt;
&amp;#x3C;/body&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;场景&lt;/strong&gt;：模态框、通知、全屏遮罩（避免 &lt;code&gt;z-index&lt;/code&gt; 嵌套问题）&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Suspense：异步加载状态&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-vue&quot;&gt;&amp;#x3C;template&gt;
  &amp;#x3C;Suspense&gt;
    &amp;#x3C;!-- 默认：异步完成显示 --&gt;
    &amp;#x3C;AsyncComponent /&gt;
    
    &amp;#x3C;!-- 加载中显示 --&gt;
    &amp;#x3C;template #fallback&gt;
      &amp;#x3C;div&gt;Loading...&amp;#x3C;/div&gt;
    &amp;#x3C;/template&gt;
  &amp;#x3C;/Suspense&gt;
&amp;#x3C;/template&gt;

&amp;#x3C;script setup&gt;
// 异步组件
const AsyncComponent = defineAsyncComponent(() =&gt; 
  import(&apos;./HeavyComponent.vue&apos;)
);
&amp;#x3C;/script&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;场景&lt;/strong&gt;：代码分割、数据获取、骨架屏&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;组合使用&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-vue&quot;&gt;&amp;#x3C;template&gt;
  &amp;#x3C;Suspense&gt;
    &amp;#x3C;template #default&gt;
      &amp;#x3C;AsyncModal /&gt;
    &amp;#x3C;/template&gt;
    &amp;#x3C;template #fallback&gt;
      &amp;#x3C;Teleport to=&quot;body&quot;&gt;
        &amp;#x3C;div class=&quot;loading-overlay&quot;&gt;加载中...&amp;#x3C;/div&gt;
      &amp;#x3C;/Teleport&gt;
    &amp;#x3C;/template&gt;
  &amp;#x3C;/Suspense&gt;
&amp;#x3C;/template&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Teleport = 去哪儿渲染&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Suspense = 什么时候渲染&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>type vs interface 关键区别</title><link>https://linme.cn/blog/%E8%AE%A1%E7%AE%97%E6%9C%BA/%E5%89%8D%E7%AB%AF/ts/type-vs-interface-%E5%85%B3%E9%94%AE%E5%8C%BA%E5%88%AB</link><guid isPermaLink="true">https://linme.cn/blog/%E8%AE%A1%E7%AE%97%E6%9C%BA/%E5%89%8D%E7%AB%AF/ts/type-vs-interface-%E5%85%B3%E9%94%AE%E5%8C%BA%E5%88%AB</guid><description>vs 关键区别</description><pubDate>Thu, 17 Jul 2025 16:19:12 GMT</pubDate><content:encoded>&lt;h2&gt;&lt;code&gt;type&lt;/code&gt; vs &lt;code&gt;interface&lt;/code&gt; 关键区别&lt;/h2&gt;
&lt;p&gt;| 特性 | &lt;code&gt;interface&lt;/code&gt; | &lt;code&gt;type&lt;/code&gt; |
|:---|:---|:---|
| &lt;strong&gt;扩展方式&lt;/strong&gt; | &lt;code&gt;extends&lt;/code&gt;（声明合并） | &lt;code&gt;&amp;#x26;&lt;/code&gt;（交叉类型） |
| &lt;strong&gt;同名声明&lt;/strong&gt; | ✅ 自动合并 | ❌ 报错（重复定义） |
| &lt;strong&gt;适用场景&lt;/strong&gt; | 对象结构、类实现 | 联合类型、元组、复杂类型运算 |
| &lt;strong&gt;性能&lt;/strong&gt; | 更快（声明合并优化） | 稍慢（需解析类型表达式） |&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;核心差异示例&lt;/h2&gt;
&lt;h3&gt;1. 扩展方式&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// interface: extends 声明式扩展
interface Animal { name: string }
interface Dog extends Animal { breed: string }

// type: &amp;#x26; 交叉类型
type Animal = { name: string }
type Dog = Animal &amp;#x26; { breed: string }
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3&gt;2. 同名合并（interface 独有）&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// ✅ interface 自动合并
interface User { name: string }
interface User { age: number }  // 合并为 { name, age }

// ❌ type 报错
type User = { name: string }
type User = { age: number }     // Error: 重复标识符
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3&gt;3. type 独有能力&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// 联合类型（interface 做不到）
type Status = &apos;pending&apos; | &apos;success&apos; | &apos;error&apos;;

// 元组
type Point = [number, number];

// 条件类型
type IsString&amp;#x3C;T&gt; = T extends string ? true : false;

// 映射类型
type ReadonlyUser = Readonly&amp;#x3C;User&gt;;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;选择建议&lt;/h2&gt;
&lt;p&gt;| 场景 | 推荐 |
|:---|:---|
| 定义对象结构、类 | &lt;code&gt;interface&lt;/code&gt; |
| 需要多次扩展同一类型 | &lt;code&gt;interface&lt;/code&gt; |
| 联合类型、元组、条件类型 | &lt;code&gt;type&lt;/code&gt; |
| 第三方库类型声明 | &lt;code&gt;interface&lt;/code&gt;（支持用户扩展） |&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>Webpack 5 模块联邦（Module Federation）</title><link>https://linme.cn/blog/%E8%AE%A1%E7%AE%97%E6%9C%BA/%E5%89%8D%E7%AB%AF/%E5%B7%A5%E7%A8%8B%E5%8C%96/webpack-5-%E6%A8%A1%E5%9D%97%E8%81%94%E9%82%A6module-federation</link><guid isPermaLink="true">https://linme.cn/blog/%E8%AE%A1%E7%AE%97%E6%9C%BA/%E5%89%8D%E7%AB%AF/%E5%B7%A5%E7%A8%8B%E5%8C%96/webpack-5-%E6%A8%A1%E5%9D%97%E8%81%94%E9%82%A6module-federation</guid><description>Webpack 5 模块联邦（Module Federation）</description><pubDate>Sun, 29 Jun 2025 07:12:50 GMT</pubDate><content:encoded>&lt;h2&gt;Webpack 5 模块联邦（Module Federation）&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;核心能力&lt;/strong&gt;：运行时动态加载远程模块，实现微前端独立部署。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;架构角色&lt;/h2&gt;
&lt;p&gt;| 角色 | 作用 | 配置 |
|:---|:---|:---|
| &lt;strong&gt;Host（宿主）&lt;/strong&gt; | 消费远程模块 | &lt;code&gt;remotes&lt;/code&gt; |
| &lt;strong&gt;Remote（远程）&lt;/strong&gt; | 暴露自身模块供他人使用 | &lt;code&gt;exposes&lt;/code&gt; |
| &lt;strong&gt;Shared（共享）&lt;/strong&gt; | 依赖共享，避免重复加载 | &lt;code&gt;shared&lt;/code&gt; |&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;代码示例&lt;/h2&gt;
&lt;h3&gt;Remote 暴露模块（独立部署）&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// webpack.config.js
const { ModuleFederationPlugin } = require(&apos;webpack&apos;).container;

module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: &apos;remoteApp&apos;,           // 远程应用名称
      filename: &apos;remoteEntry.js&apos;,   // 入口文件
      exposes: {
        &apos;./Button&apos;: &apos;./src/Button&apos;, // 暴露的模块
        &apos;./utils&apos;: &apos;./src/utils&apos;,
      },
      shared: [&apos;react&apos;, &apos;react-dom&apos;], // 共享依赖
    }),
  ],
};
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3&gt;Host 消费远程模块&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// webpack.config.js
module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: &apos;hostApp&apos;,
      remotes: {
        // 运行时动态加载
        remoteApp: &apos;remoteApp@http://localhost:3001/remoteEntry.js&apos;,
      },
      shared: [&apos;react&apos;, &apos;react-dom&apos;],
    }),
  ],
};
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;// 组件中使用远程模块
import React, { lazy, Suspense } from &apos;react&apos;;

// 动态导入远程组件
const RemoteButton = lazy(() =&gt; import(&apos;remoteApp/Button&apos;));

function App() {
  return (
    &amp;#x3C;Suspense fallback=&quot;Loading...&quot;&gt;
      &amp;#x3C;RemoteButton /&gt;  {/* 来自另一个部署！ */}
    &amp;#x3C;/Suspense&gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;共享依赖机制&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;场景：Host 和 Remote 都依赖 React

无 shared：各自打包 React，页面加载 2 份（体积大）
有 shared：运行时协商版本，只加载 1 份（自动降级/升级）
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;shared: {
  react: { 
    singleton: true,      // 强制单例
    requiredVersion: &apos;^18.0.0&apos;,
    version: &apos;18.2.0&apos;,    // 自身版本
  },
}
&lt;/code&gt;&lt;/pre&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>顺序表 + 链表</title><link>https://linme.cn/blog/%E8%AE%A1%E7%AE%97%E6%9C%BA/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/%E7%BA%BF%E5%BD%A2%E8%A1%A8/%E9%A1%BA%E5%BA%8F%E8%A1%A8--%E9%93%BE%E8%A1%A8</link><guid isPermaLink="true">https://linme.cn/blog/%E8%AE%A1%E7%AE%97%E6%9C%BA/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/%E7%BA%BF%E5%BD%A2%E8%A1%A8/%E9%A1%BA%E5%BA%8F%E8%A1%A8--%E9%93%BE%E8%A1%A8</guid><description>先记住一句话</description><pubDate>Thu, 10 Apr 2025 13:43:34 GMT</pubDate><content:encoded>&lt;h1&gt;先记住一句话&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;线性表 = 一排排好队的东西。&lt;/strong&gt;
就像：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;排队买饭&lt;/li&gt;
&lt;li&gt;一串珠子&lt;/li&gt;
&lt;li&gt;一排座位&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;特点只有 3 个：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;排成一条直线&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;有头有尾&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;中间每个人只有前面一个、后面一个&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这就叫&lt;strong&gt;线性表&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;线性表有两种排队方式&lt;/h1&gt;
&lt;h2&gt;1. 顺序表（像一排固定座位）&lt;/h2&gt;
&lt;p&gt;想象：
电影院一排座位，&lt;strong&gt;连在一起、不能拆开&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;优点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;想找第 5 个人，&lt;strong&gt;直接走过去&lt;/strong&gt;，很快。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;缺点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;中间要加人、走人，&lt;strong&gt;所有人都要挪位置&lt;/strong&gt;，麻烦。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;对应：数组&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;2. 链表（像手拉手排队）&lt;/h2&gt;
&lt;p&gt;每个人只知道：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;我是谁&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;我后面是谁&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;大家&lt;strong&gt;不坐在一起&lt;/strong&gt;，但手拉手连起来。&lt;/p&gt;
&lt;p&gt;优点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;中间加人、走人，&lt;strong&gt;只要改一下谁拉谁的手&lt;/strong&gt;，很快。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;缺点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;想找第 5 个人，&lt;strong&gt;必须从头一个一个数&lt;/strong&gt;，慢。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;对应：链表&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;最简单总结（必背）&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;线性表 = 一排东西&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;顺序表 = 连续座位，找得快，插删慢&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;链表 = 手拉手，插删快，找得慢&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>Cookie / Session / JWT 的差异是什么？登录态方案怎么选？</title><link>https://linme.cn/blog/%E5%89%8D%E7%AB%AF/js/%E5%9F%BA%E7%A1%80%E7%94%A8%E6%B3%95/%E7%BD%91%E7%BB%9C/%E5%85%B6%E4%BB%96/cookie-session-jwt-%E7%9A%84%E5%B7%AE%E5%BC%82%E6%98%AF%E4%BB%80%E4%B9%88%E7%99%BB%E5%BD%95%E6%80%81%E6%96%B9%E6%A1%88%E6%80%8E%E4%B9%88%E9%80%89</link><guid isPermaLink="true">https://linme.cn/blog/%E5%89%8D%E7%AB%AF/js/%E5%9F%BA%E7%A1%80%E7%94%A8%E6%B3%95/%E7%BD%91%E7%BB%9C/%E5%85%B6%E4%BB%96/cookie-session-jwt-%E7%9A%84%E5%B7%AE%E5%BC%82%E6%98%AF%E4%BB%80%E4%B9%88%E7%99%BB%E5%BD%95%E6%80%81%E6%96%B9%E6%A1%88%E6%80%8E%E4%B9%88%E9%80%89</guid><description>先澄清一个常见误区： 是“存/带数据的方式”， 和 是“登录态实现方式”。</description><pubDate>Wed, 09 Apr 2025 17:11:32 GMT</pubDate><content:encoded>&lt;p&gt;先澄清一个常见误区：&lt;code&gt;Cookie&lt;/code&gt; 是“存/带数据的方式”，&lt;code&gt;Session&lt;/code&gt; 和 &lt;code&gt;JWT&lt;/code&gt; 是“登录态实现方式”。&lt;/p&gt;
&lt;p&gt;| 项目 | Cookie | Session | JWT |
|---|---|---|---|
| 本质 | 浏览器存储+自动随请求发送 | 服务端保存登录状态 | 自包含的签名令牌 |
| 状态存哪 | 客户端（浏览器） | 服务端（Redis/内存/DB） | 主要在令牌里（客户端持有） |
| 服务端每次查库/查存储 | 视内容而定 | 通常要（按 sessionId 查） | 通常不用（验签即可） |
| 失效/登出控制 | 通过过期或删除 | 很容易，删 session 即可 | 较难，常靠短期过期+黑名单/轮换 |
| 典型风险 | 被窃取、CSRF（若自动带） | 会话固定、会话存储压力 | 泄露后可被重放到过期，撤销困难 |&lt;/p&gt;
&lt;p&gt;关键差异：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Session&lt;/code&gt;：最容易做“可控下线/封禁/踢人”，但有服务端状态成本。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;JWT&lt;/code&gt;：跨服务、无状态扩展好，但撤销难，设计不当安全风险更高。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Cookie&lt;/code&gt;：可承载 &lt;code&gt;sessionId&lt;/code&gt; 或 &lt;code&gt;JWT&lt;/code&gt;；不是 Session/JWT 的对立面。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;怎么选（实战）：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;传统 Web 后台、管理系统：优先 &lt;code&gt;Session + HttpOnly + Secure + SameSite Cookie&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;多端/API 网关/微服务：&lt;code&gt;短期 Access JWT + Refresh Token&lt;/code&gt;（刷新令牌要轮换）。&lt;/li&gt;
&lt;li&gt;安全要求高且要随时失效：优先 Session 或“opaque token + introspection”。&lt;/li&gt;
&lt;li&gt;Web 端尽量不要把长期 token 放 &lt;code&gt;localStorage&lt;/code&gt;（XSS 风险高）。&lt;/li&gt;
&lt;/ol&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>TypeScript 里 any / unknown / never 的区别和典型使用场景？</title><link>https://linme.cn/blog/%E8%AE%A1%E7%AE%97%E6%9C%BA/%E5%89%8D%E7%AB%AF/ts/typescript-%E9%87%8C-any-unknown-never-%E7%9A%84%E5%8C%BA%E5%88%AB%E5%92%8C%E5%85%B8%E5%9E%8B%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF</link><guid isPermaLink="true">https://linme.cn/blog/%E8%AE%A1%E7%AE%97%E6%9C%BA/%E5%89%8D%E7%AB%AF/ts/typescript-%E9%87%8C-any-unknown-never-%E7%9A%84%E5%8C%BA%E5%88%AB%E5%92%8C%E5%85%B8%E5%9E%8B%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF</guid><description>最短理解：</description><pubDate>Wed, 09 Apr 2025 17:09:27 GMT</pubDate><content:encoded>&lt;p&gt;最短理解：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;any&lt;/code&gt;：放弃类型检查（“我不管了”）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;unknown&lt;/code&gt;：暂时不知道类型，但必须先判断再用（“先验明身份”）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;never&lt;/code&gt;：不可能有值（“走不到这里”）&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;any&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;含义：可赋给任何类型，也可接收任何类型；基本跳过 TS 保护。&lt;/li&gt;
&lt;li&gt;场景：迁移旧代码、临时兜底、第三方无类型声明时短期过渡。&lt;/li&gt;
&lt;li&gt;风险：错误容易溜进运行时。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;&lt;code&gt;unknown&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;含义：类型安全版“未知值”；不能直接调用属性/方法，必须先缩小类型。&lt;/li&gt;
&lt;li&gt;场景：接口返回不可信数据、&lt;code&gt;catch (e)&lt;/code&gt;、解析外部输入（JSON/表单/消息）。&lt;/li&gt;
&lt;li&gt;优点：强制你做类型守卫，更安全。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;&lt;code&gt;never&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;含义：永远不会出现的值类型。&lt;/li&gt;
&lt;li&gt;场景：
&lt;ul&gt;
&lt;li&gt;永不返回的函数（&lt;code&gt;throw&lt;/code&gt; / 死循环）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;switch&lt;/code&gt; 穷尽检查（确保联合类型每种分支都处理了）&lt;/li&gt;
&lt;li&gt;条件类型中表示“被过滤掉的分支”&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;典型示例（&lt;code&gt;never&lt;/code&gt; 做穷尽检查）：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;type Shape = { kind: &apos;circle&apos;; r: number } | { kind: &apos;square&apos;; s: number };

function area(shape: Shape) {
  switch (shape.kind) {
    case &apos;circle&apos;: return Math.PI * shape.r ** 2;
    case &apos;square&apos;: return shape.s ** 2;
    default: {
      const _exhaustive: never = shape; // 新增 kind 未处理会在这里报错
      return _exhaustive;
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;实践建议：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;默认优先 &lt;code&gt;unknown&lt;/code&gt;，少用 &lt;code&gt;any&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;any&lt;/code&gt; 用在边界层并尽快收口。&lt;/li&gt;
&lt;li&gt;对联合类型养成 &lt;code&gt;never&lt;/code&gt; 穷尽检查习惯。&lt;/li&gt;
&lt;/ul&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>useEffect 依赖项写错常见会引发哪些 bug？如何避免闭包陷阱？</title><link>https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/useeffect-%E4%BE%9D%E8%B5%96%E9%A1%B9%E5%86%99%E9%94%99%E5%B8%B8%E8%A7%81%E4%BC%9A%E5%BC%95%E5%8F%91%E5%93%AA%E4%BA%9B-bug%E5%A6%82%E4%BD%95%E9%81%BF%E5%85%8D%E9%97%AD%E5%8C%85%E9%99%B7%E9%98%B1</link><guid isPermaLink="true">https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/useeffect-%E4%BE%9D%E8%B5%96%E9%A1%B9%E5%86%99%E9%94%99%E5%B8%B8%E8%A7%81%E4%BC%9A%E5%BC%95%E5%8F%91%E5%93%AA%E4%BA%9B-bug%E5%A6%82%E4%BD%95%E9%81%BF%E5%85%8D%E9%97%AD%E5%8C%85%E9%99%B7%E9%98%B1</guid><description>依赖写错，最常见会出这几类 bug：</description><pubDate>Wed, 09 Apr 2025 17:06:45 GMT</pubDate><content:encoded>&lt;p&gt;&lt;code&gt;useEffect&lt;/code&gt; 依赖写错，最常见会出这几类 bug：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;值“过期”（stale closure）&lt;br&gt;
&lt;code&gt;effect&lt;/code&gt; 里拿到旧的 &lt;code&gt;state/props&lt;/code&gt;，比如定时器里 &lt;code&gt;count&lt;/code&gt; 永远是旧值。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;不触发更新&lt;br&gt;
漏了依赖，参数变了但 &lt;code&gt;effect&lt;/code&gt; 不重跑，请求/订阅不更新。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;死循环或频繁重跑&lt;br&gt;
把每次 render 都新建的对象/函数放进依赖，导致反复请求、反复 setState。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;资源泄漏&lt;br&gt;
重跑时没正确清理，出现重复订阅、重复定时器、内存泄漏。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;异步竞态&lt;br&gt;
前一次慢请求后返回，覆盖后一次快请求结果（显示“旧数据”）。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;p&gt;避免闭包陷阱的实用做法：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;开启并遵守 &lt;code&gt;eslint-plugin-react-hooks&lt;/code&gt; 的 &lt;code&gt;exhaustive-deps&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;effect&lt;/code&gt; 里用到的响应式值（&lt;code&gt;props/state&lt;/code&gt;）都写进依赖。&lt;/li&gt;
&lt;li&gt;需要“基于上次值更新”时，用函数式更新：&lt;code&gt;setCount(c =&gt; c + 1)&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;不想因某值变化而重跑 &lt;code&gt;effect&lt;/code&gt;，但又要读最新值时，用 &lt;code&gt;useRef&lt;/code&gt; 保存最新值。&lt;/li&gt;
&lt;li&gt;对对象/函数依赖做稳定化：&lt;code&gt;useMemo&lt;/code&gt; / &lt;code&gt;useCallback&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;一个 &lt;code&gt;effect&lt;/code&gt; 只做一件事，拆分副作用，减少错误依赖。&lt;/li&gt;
&lt;li&gt;异步请求加取消/忽略机制（&lt;code&gt;AbortController&lt;/code&gt; 或 &lt;code&gt;ignore&lt;/code&gt; 标记）并在 cleanup 里处理。&lt;/li&gt;
&lt;li&gt;如果是 React 19，可用 &lt;code&gt;useEffectEvent&lt;/code&gt; 读取最新值，减少闭包问题。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;示例（典型闭包坑）：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;useEffect(() =&gt; {
  const id = setInterval(() =&gt; {
    setCount(count + 1); // count 是旧值
  }, 1000);
  return () =&gt; clearInterval(id);
}, []); // 漏依赖
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;改法：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;useEffect(() =&gt; {
  const id = setInterval(() =&gt; {
    setCount(c =&gt; c + 1); // 永远基于最新值
  }, 1000);
  return () =&gt; clearInterval(id);
}, []);
&lt;/code&gt;&lt;/pre&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>React 里为什么不建议用数组下标当 key？会导致什么问题？</title><link>https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/react-%E9%87%8C%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%8D%E5%BB%BA%E8%AE%AE%E7%94%A8%E6%95%B0%E7%BB%84%E4%B8%8B%E6%A0%87%E5%BD%93-key%E4%BC%9A%E5%AF%BC%E8%87%B4%E4%BB%80%E4%B9%88%E9%97%AE%E9%A2%98</link><guid isPermaLink="true">https://linme.cn/blog/%E5%89%8D%E7%AB%AF/react/react-%E9%87%8C%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%8D%E5%BB%BA%E8%AE%AE%E7%94%A8%E6%95%B0%E7%BB%84%E4%B8%8B%E6%A0%87%E5%BD%93-key%E4%BC%9A%E5%AF%BC%E8%87%B4%E4%BB%80%E4%B9%88%E9%97%AE%E9%A2%98</guid><description>在 React 里是“这个列表项是谁”的身份证。</description><pubDate>Wed, 09 Apr 2025 17:04:18 GMT</pubDate><content:encoded>&lt;p&gt;&lt;code&gt;key&lt;/code&gt; 在 React 里是“这个列表项是谁”的身份证。&lt;br&gt;
用数组下标（&lt;code&gt;index&lt;/code&gt;）当 &lt;code&gt;key&lt;/code&gt;，一旦有&lt;strong&gt;插入、删除、排序&lt;/strong&gt;，身份证就会“串号”。&lt;/p&gt;
&lt;p&gt;会导致的问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;组件状态错位&lt;br&gt;
比如第 2 行输入框内容/勾选状态跑到别的行。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;UI 交互异常&lt;br&gt;
光标跳动、输入中断、动画错位、展开/收起状态错乱。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;副作用绑定到错误项&lt;br&gt;
&lt;code&gt;useEffect&lt;/code&gt; 订阅/清理可能对应错对象。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;性能变差&lt;br&gt;
React 不能正确复用节点，出现不必要重渲染或重挂载。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;推荐做法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用&lt;strong&gt;稳定且唯一&lt;/strong&gt;的业务 ID（如数据库 &lt;code&gt;id&lt;/code&gt;）当 &lt;code&gt;key&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;没有 ID 时，在“创建数据时”生成一次 ID，不要在渲染时临时生成。&lt;/li&gt;
&lt;li&gt;只有“完全静态、不会增删改排”的列表，才勉强可用 &lt;code&gt;index&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>什么是 重排(reflow) 和 重绘(repaint)？怎么优化页面渲染性能？</title><link>https://linme.cn/blog/%E5%89%8D%E7%AB%AF/js/%E5%9F%BA%E7%A1%80%E7%94%A8%E6%B3%95/%E5%85%B6%E4%BB%96/%E4%BB%80%E4%B9%88%E6%98%AF-%E9%87%8D%E6%8E%92reflow-%E5%92%8C-%E9%87%8D%E7%BB%98repaint%E6%80%8E%E4%B9%88%E4%BC%98%E5%8C%96%E9%A1%B5%E9%9D%A2%E6%B8%B2%E6%9F%93%E6%80%A7%E8%83%BD</link><guid isPermaLink="true">https://linme.cn/blog/%E5%89%8D%E7%AB%AF/js/%E5%9F%BA%E7%A1%80%E7%94%A8%E6%B3%95/%E5%85%B6%E4%BB%96/%E4%BB%80%E4%B9%88%E6%98%AF-%E9%87%8D%E6%8E%92reflow-%E5%92%8C-%E9%87%8D%E7%BB%98repaint%E6%80%8E%E4%B9%88%E4%BC%98%E5%8C%96%E9%A1%B5%E9%9D%A2%E6%B8%B2%E6%9F%93%E6%80%A7%E8%83%BD</guid><description>概念区别</description><pubDate>Wed, 09 Apr 2025 16:47:08 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;概念区别&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;重排（Reflow / Layout）&lt;/strong&gt;&lt;br&gt;
浏览器要重新计算元素的几何信息：位置、宽高、布局关系。&lt;br&gt;
典型触发：改 &lt;code&gt;width/height/padding/margin&lt;/code&gt;、改 &lt;code&gt;display&lt;/code&gt;、增删 DOM、窗口 resize。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;重绘（Repaint）&lt;/strong&gt;&lt;br&gt;
不改几何信息，只改外观，浏览器重新“上色”。&lt;br&gt;
典型触发：改 &lt;code&gt;color/background/box-shadow&lt;/code&gt; 等。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;关系&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;重排一定会引发重绘&lt;/strong&gt;，重绘不一定重排。&lt;br&gt;
所以重排通常更贵、性能影响更大。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;怎么优化渲染性能&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;少做会触发布局的改动&lt;/strong&gt;&lt;br&gt;
尽量用一次性改 class，避免频繁逐条改样式。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;读写分离，避免布局抖动（layout thrashing）&lt;/strong&gt;&lt;br&gt;
先批量读布局（如 &lt;code&gt;offsetWidth&lt;/code&gt;），再批量写样式，不要读写交替。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;动画优先用 &lt;code&gt;transform&lt;/code&gt; 和 &lt;code&gt;opacity&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
尽量避免动画改 &lt;code&gt;top/left/width/height&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;批量更新 DOM&lt;/strong&gt;&lt;br&gt;
用 &lt;code&gt;DocumentFragment&lt;/code&gt;、一次性插入；复杂更新可先隐藏容器再显示。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;减少渲染范围和复杂度&lt;/strong&gt;&lt;br&gt;
简化 DOM 层级，长列表用虚拟列表（只渲染可视区）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;合理使用新特性隔离开销&lt;/strong&gt;&lt;br&gt;
可用 &lt;code&gt;contain&lt;/code&gt;、&lt;code&gt;content-visibility&lt;/code&gt; 限制重排影响范围；&lt;code&gt;will-change&lt;/code&gt; 谨慎使用。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;用 DevTools 定位热点&lt;/strong&gt;&lt;br&gt;
在 Performance 面板看 Layout/Paint 开销，优先优化高频和长耗时操作。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>浏览器 Event Loop 中，宏任务 和 微任务 的执行顺序是什么？</title><link>https://linme.cn/blog/%E5%89%8D%E7%AB%AF/js/%E5%9F%BA%E7%A1%80%E7%94%A8%E6%B3%95/%E5%85%B6%E4%BB%96/%E6%B5%8F%E8%A7%88%E5%99%A8-event-loop-%E4%B8%AD%E5%AE%8F%E4%BB%BB%E5%8A%A1-%E5%92%8C-%E5%BE%AE%E4%BB%BB%E5%8A%A1-%E7%9A%84%E6%89%A7%E8%A1%8C%E9%A1%BA%E5%BA%8F%E6%98%AF%E4%BB%80%E4%B9%88</link><guid isPermaLink="true">https://linme.cn/blog/%E5%89%8D%E7%AB%AF/js/%E5%9F%BA%E7%A1%80%E7%94%A8%E6%B3%95/%E5%85%B6%E4%BB%96/%E6%B5%8F%E8%A7%88%E5%99%A8-event-loop-%E4%B8%AD%E5%AE%8F%E4%BB%BB%E5%8A%A1-%E5%92%8C-%E5%BE%AE%E4%BB%BB%E5%8A%A1-%E7%9A%84%E6%89%A7%E8%A1%8C%E9%A1%BA%E5%BA%8F%E6%98%AF%E4%BB%80%E4%B9%88</guid><description>执行顺序可以记成一句话：</description><pubDate>Wed, 09 Apr 2025 16:44:31 GMT</pubDate><content:encoded>&lt;p&gt;执行顺序可以记成一句话：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;先跑一个宏任务，再把微任务队列清空，再进行渲染，然后进入下一个宏任务。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;简化流程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;取出并执行 1 个&lt;strong&gt;宏任务&lt;/strong&gt;（&lt;code&gt;script&lt;/code&gt;、&lt;code&gt;setTimeout&lt;/code&gt;、I/O、UI 事件等）&lt;/li&gt;
&lt;li&gt;执行完后，立即把当前所有&lt;strong&gt;微任务&lt;/strong&gt;全部执行完（&lt;code&gt;Promise.then&lt;/code&gt;、&lt;code&gt;queueMicrotask&lt;/code&gt;、&lt;code&gt;MutationObserver&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;微任务清空后，浏览器才有机会做一次渲染&lt;/li&gt;
&lt;li&gt;进入下一轮，继续取下一个宏任务&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;补充重点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;微任务会“插队”到下一个宏任务之前。&lt;/li&gt;
&lt;li&gt;如果微任务不断自我追加，可能长期阻塞渲染和后续宏任务。&lt;/li&gt;
&lt;/ul&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>HTTPS 相比 HTTP 多了哪些核心步骤？证书校验主要在防什么？</title><link>https://linme.cn/blog/%E5%89%8D%E7%AB%AF/js/%E5%9F%BA%E7%A1%80%E7%94%A8%E6%B3%95/%E7%BD%91%E7%BB%9C/http/https-%E7%9B%B8%E6%AF%94-http-%E5%A4%9A%E4%BA%86%E5%93%AA%E4%BA%9B%E6%A0%B8%E5%BF%83%E6%AD%A5%E9%AA%A4%E8%AF%81%E4%B9%A6%E6%A0%A1%E9%AA%8C%E4%B8%BB%E8%A6%81%E5%9C%A8%E9%98%B2%E4%BB%80%E4%B9%88</link><guid isPermaLink="true">https://linme.cn/blog/%E5%89%8D%E7%AB%AF/js/%E5%9F%BA%E7%A1%80%E7%94%A8%E6%B3%95/%E7%BD%91%E7%BB%9C/http/https-%E7%9B%B8%E6%AF%94-http-%E5%A4%9A%E4%BA%86%E5%93%AA%E4%BA%9B%E6%A0%B8%E5%BF%83%E6%AD%A5%E9%AA%A4%E8%AF%81%E4%B9%A6%E6%A0%A1%E9%AA%8C%E4%B8%BB%E8%A6%81%E5%9C%A8%E9%98%B2%E4%BB%80%E4%B9%88</guid><description>HTTPS 比 HTTP 多的核心步骤</description><pubDate>Wed, 09 Apr 2025 16:42:01 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;HTTPS 比 HTTP 多的核心步骤&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;HTTP 通常是：&lt;code&gt;TCP 连接 -&gt; 直接发 HTTP 明文请求&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;HTTPS 通常是：&lt;code&gt;TCP(或 QUIC)连接 -&gt; TLS 握手 -&gt; 再发 HTTP(加密)&lt;/code&gt;
多出来的关键是 &lt;strong&gt;TLS 握手&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;客户端发 &lt;code&gt;ClientHello&lt;/code&gt;（支持的 TLS 版本、加密套件、SNI、ALPN 等）&lt;/li&gt;
&lt;li&gt;服务端回 &lt;code&gt;ServerHello&lt;/code&gt; + 证书链（并选定加密参数）&lt;/li&gt;
&lt;li&gt;客户端做证书校验（域名、有效期、签名链、是否受信任等）&lt;/li&gt;
&lt;li&gt;双方做密钥交换（常见 ECDHE），生成会话密钥&lt;/li&gt;
&lt;li&gt;发送 &lt;code&gt;Finished&lt;/code&gt;，后续 HTTP 数据全部加密传输&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;证书校验主要在防什么&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;核心是在防 &lt;strong&gt;“你以为连的是A站，实际连到攻击者”&lt;/strong&gt;，也就是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;中间人攻击（MITM）&lt;/li&gt;
&lt;li&gt;假冒网站/伪造服务器身份&lt;/li&gt;
&lt;li&gt;DNS/路由劫持后被导向假站&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;本质上保障三件事：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;身份真实性&lt;/strong&gt;（确实是目标域名对应服务器）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;传输机密性&lt;/strong&gt;（内容不被窃听）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;传输完整性&lt;/strong&gt;（内容不被篡改）&lt;/li&gt;
&lt;/ul&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>TCP 三次握手 为什么不是两次？TIME_WAIT 的意义是什么？</title><link>https://linme.cn/blog/%E5%89%8D%E7%AB%AF/js/%E5%9F%BA%E7%A1%80%E7%94%A8%E6%B3%95/%E7%BD%91%E7%BB%9C/t-c-p/tcp-%E4%B8%89%E6%AC%A1%E6%8F%A1%E6%89%8B-%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%8D%E6%98%AF%E4%B8%A4%E6%AC%A1time_wait-%E7%9A%84%E6%84%8F%E4%B9%89%E6%98%AF%E4%BB%80%E4%B9%88</link><guid isPermaLink="true">https://linme.cn/blog/%E5%89%8D%E7%AB%AF/js/%E5%9F%BA%E7%A1%80%E7%94%A8%E6%B3%95/%E7%BD%91%E7%BB%9C/t-c-p/tcp-%E4%B8%89%E6%AC%A1%E6%8F%A1%E6%89%8B-%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%8D%E6%98%AF%E4%B8%A4%E6%AC%A1time_wait-%E7%9A%84%E6%84%8F%E4%B9%89%E6%98%AF%E4%BB%80%E4%B9%88</guid><description>为什么 TCP 要三次握手，不是两次？</description><pubDate>Wed, 09 Apr 2025 16:33:21 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;为什么 TCP 要三次握手，不是两次？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;三次握手的目标是：&lt;strong&gt;双方都确认“我能发、我能收”，并且同步各自初始序号&lt;/strong&gt;。&lt;br&gt;
流程是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;客户端发 &lt;code&gt;SYN(seq=x)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;服务端回 &lt;code&gt;SYN+ACK(seq=y, ack=x+1)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;客户端再回 &lt;code&gt;ACK(ack=y+1)&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果只有两次，会有两个问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;服务端无法确认客户端是否收到了第 2 步（&lt;code&gt;SYN+ACK&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;旧的、延迟到达的 &lt;code&gt;SYN&lt;/code&gt; 可能让服务端误建连接（“幽灵连接”）。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;第 3 次 ACK 本质上是客户端给服务端的“确认回执”，证明这次连接是有效且双向可用的。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;TIME_WAIT&lt;/code&gt; 的意义是什么？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;TIME_WAIT&lt;/code&gt; 出现在&lt;strong&gt;主动关闭连接的一方&lt;/strong&gt;，停留约 &lt;code&gt;2MSL&lt;/code&gt;（实现相关，通常几十秒到几分钟）。&lt;/p&gt;
&lt;p&gt;主要有两大作用：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;保证连接可靠结束&lt;/strong&gt;&lt;br&gt;
如果最后一个 ACK 丢了，对方会重发 FIN；&lt;code&gt;TIME_WAIT&lt;/code&gt; 期间还能再回 ACK。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;防止旧报文污染新连接&lt;/strong&gt;&lt;br&gt;
等旧连接中的延迟包在网络中自然过期，避免和同四元组（源/目的 IP+端口）的新连接混淆。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;所以 &lt;code&gt;TIME_WAIT&lt;/code&gt; 是 TCP 为了“正确性和安全性”付出的必要代价，不是无意义等待。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>说下 HTTP 强缓存 和 协商缓存 的区别，分别看哪些响应头/请求头？</title><link>https://linme.cn/blog/%E5%89%8D%E7%AB%AF/js/%E5%9F%BA%E7%A1%80%E7%94%A8%E6%B3%95/%E7%BD%91%E7%BB%9C/http/%E8%AF%B4%E4%B8%8B-http-%E5%BC%BA%E7%BC%93%E5%AD%98-%E5%92%8C-%E5%8D%8F%E5%95%86%E7%BC%93%E5%AD%98-%E7%9A%84%E5%8C%BA%E5%88%AB%E5%88%86%E5%88%AB%E7%9C%8B%E5%93%AA%E4%BA%9B%E5%93%8D%E5%BA%94%E5%A4%B4-%E8%AF%B7%E6%B1%82%E5%A4%B4</link><guid isPermaLink="true">https://linme.cn/blog/%E5%89%8D%E7%AB%AF/js/%E5%9F%BA%E7%A1%80%E7%94%A8%E6%B3%95/%E7%BD%91%E7%BB%9C/http/%E8%AF%B4%E4%B8%8B-http-%E5%BC%BA%E7%BC%93%E5%AD%98-%E5%92%8C-%E5%8D%8F%E5%95%86%E7%BC%93%E5%AD%98-%E7%9A%84%E5%8C%BA%E5%88%AB%E5%88%86%E5%88%AB%E7%9C%8B%E5%93%AA%E4%BA%9B%E5%93%8D%E5%BA%94%E5%A4%B4-%E8%AF%B7%E6%B1%82%E5%A4%B4</guid><description>核心区别一句话：</description><pubDate>Wed, 09 Apr 2025 16:27:07 GMT</pubDate><content:encoded>&lt;p&gt;核心区别一句话：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;强缓存&lt;/strong&gt;：浏览器自己判断“还没过期”，&lt;strong&gt;不发请求&lt;/strong&gt;，直接用本地副本。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;协商缓存&lt;/strong&gt;：浏览器会发请求问服务器“资源变没变”，由服务器决定用旧的还是新的。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;分别看哪些头：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;强缓存&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;主要看&lt;strong&gt;响应头&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Cache-Control&lt;/code&gt;（最重要，尤其 &lt;code&gt;max-age&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Expires&lt;/code&gt;（老方案，兼容用）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;请求头&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;命中强缓存时通常没有对应网络请求（所以也就没有验证类请求头）&lt;/li&gt;
&lt;li&gt;若用户强刷/禁缓存，可能带 &lt;code&gt;Cache-Control: no-cache&lt;/code&gt;、&lt;code&gt;Pragma: no-cache&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;&lt;strong&gt;协商缓存&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;服务器下发的&lt;strong&gt;响应头&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ETag&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Last-Modified&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;浏览器下次请求带的&lt;strong&gt;请求头&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;If-None-Match&lt;/code&gt;（对应 &lt;code&gt;ETag&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;If-Modified-Since&lt;/code&gt;（对应 &lt;code&gt;Last-Modified&lt;/code&gt;）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;返回结果：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;未变化：&lt;code&gt;304 Not Modified&lt;/code&gt;（通常无响应体，继续用本地）&lt;/li&gt;
&lt;li&gt;已变化：&lt;code&gt;200 OK&lt;/code&gt; + 新内容（并更新 &lt;code&gt;ETag/Last-Modified&lt;/code&gt;）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;补充：实际流程通常是&lt;strong&gt;先看强缓存&lt;/strong&gt;，强缓存不命中再走协商缓存。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>从输入 URL 到页面渲染完成，关键链路有哪些阶段？</title><link>https://linme.cn/blog/%E5%89%8D%E7%AB%AF/js/%E5%9F%BA%E7%A1%80%E7%94%A8%E6%B3%95/%E7%BD%91%E7%BB%9C/%E5%85%B6%E4%BB%96/%E4%BB%8E%E8%BE%93%E5%85%A5-url-%E5%88%B0%E9%A1%B5%E9%9D%A2%E6%B8%B2%E6%9F%93%E5%AE%8C%E6%88%90%E5%85%B3%E9%94%AE%E9%93%BE%E8%B7%AF%E6%9C%89%E5%93%AA%E4%BA%9B%E9%98%B6%E6%AE%B5</link><guid isPermaLink="true">https://linme.cn/blog/%E5%89%8D%E7%AB%AF/js/%E5%9F%BA%E7%A1%80%E7%94%A8%E6%B3%95/%E7%BD%91%E7%BB%9C/%E5%85%B6%E4%BB%96/%E4%BB%8E%E8%BE%93%E5%85%A5-url-%E5%88%B0%E9%A1%B5%E9%9D%A2%E6%B8%B2%E6%9F%93%E5%AE%8C%E6%88%90%E5%85%B3%E9%94%AE%E9%93%BE%E8%B7%AF%E6%9C%89%E5%93%AA%E4%BA%9B%E9%98%B6%E6%AE%B5</guid><description>1. 关键链路阶段</description><pubDate>Wed, 09 Apr 2025 16:15:16 GMT</pubDate><content:encoded>&lt;h2&gt;1. 关键链路阶段&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;URL 解析&lt;/strong&gt;&lt;br&gt;
浏览器解析地址（协议、域名、路径、参数等），确认要访问什么资源。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;浏览器预检查&lt;/strong&gt;&lt;br&gt;
先检查是否可直接使用本地结果：缓存、&lt;code&gt;Service Worker&lt;/code&gt;、&lt;code&gt;HSTS&lt;/code&gt;、已有连接复用。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;DNS 解析&lt;/strong&gt;&lt;br&gt;
把域名（如 &lt;code&gt;example.com&lt;/code&gt;）转换成服务器 &lt;code&gt;IP&lt;/code&gt; 地址。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;建立连接&lt;/strong&gt;&lt;br&gt;
根据协议建立网络通道：&lt;code&gt;TCP + TLS&lt;/code&gt;（HTTP/1.1、HTTP/2）或 &lt;code&gt;QUIC&lt;/code&gt;（HTTP/3）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;发送 HTTP 请求&lt;/strong&gt;&lt;br&gt;
浏览器发送请求，请求里包含 &lt;code&gt;Headers&lt;/code&gt;、&lt;code&gt;Cookie&lt;/code&gt; 等信息。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;服务端处理并返回首包&lt;/strong&gt;&lt;br&gt;
服务器处理请求并开始返回数据，直到收到首字节（&lt;code&gt;TTFB&lt;/code&gt;）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;流式接收 HTML 并发现子资源&lt;/strong&gt;&lt;br&gt;
浏览器边收 HTML 边解析，同时继续请求 CSS、JS、图片、字体等资源。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;构建页面模型并执行脚本&lt;/strong&gt;&lt;br&gt;
构建 &lt;code&gt;DOM&lt;/code&gt; 和 &lt;code&gt;CSSOM&lt;/code&gt;，执行 &lt;code&gt;JS&lt;/code&gt;（某些 JS 会阻塞解析和渲染）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;生成可渲染结构并计算布局&lt;/strong&gt;&lt;br&gt;
合成渲染树（&lt;code&gt;Render Tree&lt;/code&gt;），做 &lt;code&gt;Layout&lt;/code&gt;（计算元素大小和位置）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;绘制与合成上屏&lt;/strong&gt;&lt;br&gt;
先 &lt;code&gt;Paint&lt;/code&gt;（绘制像素），再 &lt;code&gt;Composite&lt;/code&gt;（图层合成）显示到屏幕，后续继续补齐剩余内容。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2&gt;2. 专有名词解释&lt;/h2&gt;
&lt;p&gt;| 名词 | 解释 |
|---|---|
| URL | 网页地址，如 &lt;code&gt;https://example.com/a?b=1&lt;/code&gt; |
| Service Worker | 网页的本地代理脚本，可拦截请求、做离线缓存 |
| HSTS | 强制使用 HTTPS 的安全策略，防止降级到不安全 HTTP |
| DNS | 域名解析系统，把域名翻译成 IP |
| IP | 服务器在网络中的数字地址 |
| TCP | 可靠传输协议，保证数据按序到达 |
| TLS | 传输加密层，保证通信安全（HTTPS 基础） |
| QUIC | 基于 UDP 的现代传输协议，HTTP/3 使用它 |
| HTTP/1.1、HTTP/2、HTTP/3 | 浏览器与服务器通信协议的不同版本 |
| Headers | 请求/响应附带的元信息（语言、压缩、缓存策略等） |
| Cookie | 浏览器保存的小数据（登录态、会话、偏好） |
| TTFB | Time To First Byte，收到响应首字节的时间 |
| Layout | 计算每个元素的位置和尺寸（回流） |
| Paint | 把文本、颜色、边框等绘制成像素 |
| Composite | 把多个图层合成为最终画面并显示 |
| FCP | 首次内容绘制，用户第一次看到内容 |
| LCP | 最大内容绘制，主内容出现的关键时刻 |
| load | 页面 &lt;code&gt;load&lt;/code&gt; 事件触发，通常表示资源基本加载完成 |&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>Vi/Vim 编辑文件的核心常用命令</title><link>https://linme.cn/blog/%E8%AE%A1%E7%AE%97%E6%9C%BA/linux/vi-vim-%E7%BC%96%E8%BE%91%E6%96%87%E4%BB%B6%E7%9A%84%E6%A0%B8%E5%BF%83%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4</link><guid isPermaLink="true">https://linme.cn/blog/%E8%AE%A1%E7%AE%97%E6%9C%BA/linux/vi-vim-%E7%BC%96%E8%BE%91%E6%96%87%E4%BB%B6%E7%9A%84%E6%A0%B8%E5%BF%83%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4</guid><description>Vi/Vim 编辑文件的核心常用命令</description><pubDate>Thu, 20 Mar 2025 15:45:46 GMT</pubDate><content:encoded>&lt;h3&gt;Vi/Vim 编辑文件的核心常用命令&lt;/h3&gt;
&lt;h4&gt;一、基础模式切换（最核心）&lt;/h4&gt;
&lt;p&gt;| 操作 | 命令 | 说明 |
|------|------|------|
| 进入插入模式（编辑文本） | &lt;code&gt;i&lt;/code&gt; | 在光标&lt;strong&gt;当前位置&lt;/strong&gt;插入（最常用） |
| 进入插入模式 | &lt;code&gt;a&lt;/code&gt; | 在光标&lt;strong&gt;下一个字符&lt;/strong&gt;后插入 |
| 进入插入模式 | &lt;code&gt;o&lt;/code&gt; | 在光标&lt;strong&gt;下一行&lt;/strong&gt;新建一行并插入 |
| 进入插入模式 | &lt;code&gt;I&lt;/code&gt; | 跳到当前行&lt;strong&gt;行首&lt;/strong&gt;插入 |
| 进入插入模式 | &lt;code&gt;A&lt;/code&gt; | 跳到当前行&lt;strong&gt;行尾&lt;/strong&gt;插入 |
| 退出插入模式（回到命令模式） | &lt;code&gt;Esc&lt;/code&gt; | 按一次即可，编辑完必按 |
| 进入末行模式（保存/退出/查找） | &lt;code&gt;:&lt;/code&gt; | 命令模式下按 &lt;code&gt;:&lt;/code&gt;，底部会出现 &lt;code&gt;:&lt;/code&gt; 提示符 |&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;二、文本编辑（命令模式下）&lt;/h4&gt;
&lt;h5&gt;1. 光标移动（不用鼠标！）&lt;/h5&gt;
&lt;p&gt;| 命令 | 说明 |
|------|------|
| &lt;code&gt;h/j/k/l&lt;/code&gt; | 左/下/上/右移动（替代方向键，老手必备） |
| &lt;code&gt;0&lt;/code&gt; | 跳到当前行&lt;strong&gt;行首&lt;/strong&gt;（数字 0） |
| &lt;code&gt;$&lt;/code&gt; | 跳到当前行&lt;strong&gt;行尾&lt;/strong&gt; |
| &lt;code&gt;gg&lt;/code&gt; | 跳到文件&lt;strong&gt;第一行&lt;/strong&gt; |
| &lt;code&gt;G&lt;/code&gt; | 跳到文件&lt;strong&gt;最后一行&lt;/strong&gt; |
| &lt;code&gt;5G&lt;/code&gt; | 跳到第 5 行（替换数字可跳任意行） |
| &lt;code&gt;w&lt;/code&gt; | 跳到下一个单词开头 |
| &lt;code&gt;b&lt;/code&gt; | 跳到上一个单词开头 |&lt;/p&gt;
&lt;h5&gt;2. 复制/粘贴/删除&lt;/h5&gt;
&lt;p&gt;| 命令 | 说明 |
|------|------|
| &lt;code&gt;yy&lt;/code&gt; | 复制当前行（最常用，「yank」缩写） |
| &lt;code&gt;5yy&lt;/code&gt; | 复制从当前行开始的 5 行 |
| &lt;code&gt;p&lt;/code&gt; | 粘贴到光标下一行（「paste」缩写） |
| &lt;code&gt;P&lt;/code&gt; | 粘贴到光标上一行 |
| &lt;code&gt;dd&lt;/code&gt; | 删除当前行（「delete」缩写，最常用） |
| &lt;code&gt;5dd&lt;/code&gt; | 删除从当前行开始的 5 行 |
| &lt;code&gt;x&lt;/code&gt; | 删除光标所在字符（按 Delete 键效果一样） |
| &lt;code&gt;dw&lt;/code&gt; | 删除光标所在单词 |
| &lt;code&gt;u&lt;/code&gt; | 撤销上一步操作（「undo」，改错必用） |
| &lt;code&gt;Ctrl + r&lt;/code&gt; | 恢复撤销的操作（「redo」） |&lt;/p&gt;
&lt;h5&gt;3. 快速修改&lt;/h5&gt;
&lt;p&gt;| 命令 | 说明 |
|------|------|
| &lt;code&gt;r&lt;/code&gt; | 替换光标所在字符（比如 &lt;code&gt;ra&lt;/code&gt; 把当前字符改成 a） |
| &lt;code&gt;cc&lt;/code&gt; | 清空当前行并进入插入模式 |
| &lt;code&gt;cw&lt;/code&gt; | 清空当前单词并进入插入模式 |&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;三、保存/退出（末行模式下，先按 &lt;code&gt;:&lt;/code&gt; 再输命令）&lt;/h4&gt;
&lt;p&gt;| 命令 | 说明 |
|------|------|
| &lt;code&gt;:w&lt;/code&gt; | 保存文件（「write」，只保存不退出） |
| &lt;code&gt;:w test.txt&lt;/code&gt; | 另存为 test.txt（指定新文件名） |
| &lt;code&gt;:q&lt;/code&gt; | 退出编辑器（文件未修改时可用） |
| &lt;code&gt;:q!&lt;/code&gt; | 强制退出，&lt;strong&gt;放弃所有修改&lt;/strong&gt;（改错不想保存必用） |
| &lt;code&gt;:wq&lt;/code&gt; | 保存并退出（最常用，等价于 &lt;code&gt;:x&lt;/code&gt;） |
| &lt;code&gt;:x&lt;/code&gt; | 保存并退出（比 &lt;code&gt;:wq&lt;/code&gt; 更智能：文件没修改时不会额外写入） |&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;四、查找/替换（末行模式下）&lt;/h4&gt;
&lt;h5&gt;1. 查找&lt;/h5&gt;
&lt;p&gt;| 命令 | 说明 |
|------|------|
| &lt;code&gt;:/关键词&lt;/code&gt; | 从光标处向下查找「关键词」（比如 &lt;code&gt;:/codex&lt;/code&gt; 查找 codex） |
| &lt;code&gt;:?关键词&lt;/code&gt; | 从光标处向上查找「关键词」 |
| &lt;code&gt;n&lt;/code&gt; | 跳转到下一个匹配结果 |
| &lt;code&gt;N&lt;/code&gt; | 跳转到上一个匹配结果 |&lt;/p&gt;
&lt;h5&gt;2. 替换（新手必学）&lt;/h5&gt;
&lt;p&gt;| 命令 | 说明 |
|------|------|
| &lt;code&gt;:%s/旧内容/新内容/g&lt;/code&gt; | 全局替换（整个文件的旧内容换成新内容）比如 &lt;code&gt;:%s/codex/CODEX/g&lt;/code&gt; 把所有 codex 换成 CODEX |
| &lt;code&gt;:1,10s/旧内容/新内容/g&lt;/code&gt; | 替换 1-10 行的旧内容 |
| &lt;code&gt;:s/旧内容/新内容/g&lt;/code&gt; | 只替换当前行的旧内容 |
| 补充 | &lt;code&gt;g&lt;/code&gt; 表示「全局」，不加则只替换每行第一个匹配项；加 &lt;code&gt;c&lt;/code&gt; 表示确认替换（&lt;code&gt;:%s/旧/新/gc&lt;/code&gt;），避免误替换 |&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>闭包</title><link>https://linme.cn/blog/%E5%89%8D%E7%AB%AF/js/%E5%9F%BA%E7%A1%80%E7%94%A8%E6%B3%95/%E5%85%B6%E4%BB%96/%E9%97%AD%E5%8C%85</link><guid isPermaLink="true">https://linme.cn/blog/%E5%89%8D%E7%AB%AF/js/%E5%9F%BA%E7%A1%80%E7%94%A8%E6%B3%95/%E5%85%B6%E4%BB%96/%E9%97%AD%E5%8C%85</guid><description>闭包（Closure） ：</description><pubDate>Sat, 01 Mar 2025 15:11:35 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;闭包（Closure）&lt;/strong&gt;：&lt;br&gt;
就是“&lt;strong&gt;函数 + 它定义时所在作用域里的变量&lt;/strong&gt;”打包在一起。&lt;br&gt;
即使这个函数在作用域外执行，仍然能访问当时的变量。&lt;/p&gt;
&lt;h3&gt;例子（JavaScript）&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;function outer() {
  let count = 0;
  return function inner() {
    count++;
    return count;
  };
}

const fn = outer();
console.log(fn()); // 1
console.log(fn()); // 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里 &lt;code&gt;inner&lt;/code&gt; 就是闭包：&lt;br&gt;
它记住了 &lt;code&gt;outer&lt;/code&gt; 里的 &lt;code&gt;count&lt;/code&gt;，所以 &lt;code&gt;outer&lt;/code&gt; 执行完后，&lt;code&gt;count&lt;/code&gt; 还在。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>iPhone Files 连接 Windows 共享文件夹完整指南（含重启IP提醒）</title><link>https://linme.cn/blog/%E5%85%B6%E4%BB%96/iphone-files-%E8%BF%9E%E6%8E%A5-windows-%E5%85%B1%E4%BA%AB%E6%96%87%E4%BB%B6%E5%A4%B9%E5%AE%8C%E6%95%B4%E6%8C%87%E5%8D%97%E5%90%AB%E9%87%8D%E5%90%AFip%E6%8F%90%E9%86%92</link><guid isPermaLink="true">https://linme.cn/blog/%E5%85%B6%E4%BB%96/iphone-files-%E8%BF%9E%E6%8E%A5-windows-%E5%85%B1%E4%BA%AB%E6%96%87%E4%BB%B6%E5%A4%B9%E5%AE%8C%E6%95%B4%E6%8C%87%E5%8D%97%E5%90%AB%E9%87%8D%E5%90%AFip%E6%8F%90%E9%86%92</guid><description>⚠️ 核心重要提醒</description><pubDate>Tue, 28 Jan 2025 18:41:15 GMT</pubDate><content:encoded>&lt;h2&gt;⚠️ 核心重要提醒&lt;/h2&gt;
&lt;p&gt;电脑重启后，若未设置静态IP，系统会通过DHCP自动获取新的IP地址，直接导致iPhone Files中保存的旧地址失效，出现「Socket is not connected」「无法连接服务器」等报错，这是重启后连接失败的最常见诱因。本指南优先提供静态IP固定方案，彻底规避此问题。&lt;/p&gt;
&lt;h2&gt;一、前期准备&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;iPhone与Windows电脑必须连接&lt;strong&gt;同一个Wi-Fi网络&lt;/strong&gt;，确保处于同一局域网内&lt;/li&gt;
&lt;li&gt;Windows电脑建议使用&lt;strong&gt;本地账户&lt;/strong&gt;登录（Microsoft在线账户连接时易出现权限校验失败问题）&lt;/li&gt;
&lt;li&gt;提前确定需共享的文件夹，建议命名为纯英文/数字，无空格、特殊字符，避免连接异常&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;二、Windows电脑端完整配置&lt;/h2&gt;
&lt;h3&gt;1. 固定电脑IP地址（彻底解决重启换IP问题）&lt;/h3&gt;
&lt;p&gt;两种方案任选其一，优先推荐路由器端绑定，稳定性更强。&lt;/p&gt;
&lt;h4&gt;方案A：路由器端静态IP/MAC地址绑定（推荐）&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;打开浏览器，输入路由器管理后台地址（通常为&lt;code&gt;192.168.1.1&lt;/code&gt;/&lt;code&gt;192.168.0.1&lt;/code&gt;，可在路由器机身背面查看），登录管理账号&lt;/li&gt;
&lt;li&gt;在后台找到「DHCP静态分配」「IP与MAC地址绑定」或同类功能入口（不同品牌路由器命名略有差异）&lt;/li&gt;
&lt;li&gt;Windows端按下&lt;code&gt;Win+R&lt;/code&gt;，输入&lt;code&gt;cmd&lt;/code&gt;打开命令提示符，执行&lt;code&gt;ipconfig /all&lt;/code&gt;，找到当前连接的Wi-Fi/以太网适配器，记录下**物理地址（MAC地址）**与当前IPv4地址&lt;/li&gt;
&lt;li&gt;在路由器绑定页面，填入电脑的MAC地址、想要固定的IPv4地址（与当前网段一致，如&lt;code&gt;192.168.1.100&lt;/code&gt;），保存设置并重启路由器生效&lt;/li&gt;
&lt;li&gt;生效后，无论电脑如何重启，路由器都会给该设备分配固定的IP地址，不会出现地址变动&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;方案B：Windows系统手动设置静态IP&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;打开Windows「设置」→「网络和Internet」，选择当前连接的Wi-Fi/以太网，点击「属性」&lt;/li&gt;
&lt;li&gt;找到「IP设置」板块，点击「编辑」，将自动获取(DHCP)切换为「手动」&lt;/li&gt;
&lt;li&gt;开启IPv4选项，按以下规则填写参数：
&lt;ul&gt;
&lt;li&gt;IP地址：填写与路由器同网段的固定地址（如&lt;code&gt;192.168.1.100&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;子网前缀长度：&lt;code&gt;24&lt;/code&gt;（对应子网掩码&lt;code&gt;255.255.255.0&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;网关：填写路由器管理后台地址（如&lt;code&gt;192.168.1.1&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;首选DNS：&lt;code&gt;114.114.114.114&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;备用DNS：&lt;code&gt;8.8.8.8&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;点击「保存」，IP地址固定完成&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;2. 开启并配置共享相关服务&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;按下&lt;code&gt;Win+R&lt;/code&gt;，输入&lt;code&gt;services.msc&lt;/code&gt;打开系统服务面板&lt;/li&gt;
&lt;li&gt;在服务列表中找到&lt;strong&gt;Server&lt;/strong&gt;服务，双击打开属性面板：
&lt;ul&gt;
&lt;li&gt;启动类型设置为「自动」&lt;/li&gt;
&lt;li&gt;若服务未运行，点击「启动」&lt;/li&gt;
&lt;li&gt;切换到「恢复」选项卡，将第一次/第二次/后续失败的操作均设置为「重新启动服务」，点击应用保存&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;同路径找到&lt;strong&gt;TCP/IP NetBIOS Helper&lt;/strong&gt;服务，同样设置为「自动」启动，并确保服务处于运行状态&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;3. 防火墙放行共享连接&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;打开「Windows安全中心」→「防火墙和网络保护」→「允许应用通过防火墙」&lt;/li&gt;
&lt;li&gt;点击页面上方的「更改设置」获取管理员权限&lt;/li&gt;
&lt;li&gt;在应用列表中找到&lt;strong&gt;文件和打印机共享&lt;/strong&gt;，勾选对应的网络类型（家庭/工作网络勾选「专用」，公共网络可按需勾选「公用」）&lt;/li&gt;
&lt;li&gt;确认后保存设置，避免防火墙拦截iPhone的SMB连接请求&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;4. 关闭网卡节能设置（避免休眠断连）&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;右键开始菜单，选择「设备管理器」&lt;/li&gt;
&lt;li&gt;展开「网络适配器」列表，找到当前使用的Wi-Fi/以太网卡，双击打开属性面板&lt;/li&gt;
&lt;li&gt;切换到「电源管理」选项卡，取消勾选&lt;strong&gt;允许计算机关闭此设备以节约电源&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;点击确定保存，避免电脑休眠或重启后网卡被系统关闭导致断连&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;5. 配置共享文件夹权限&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;右键需要共享的文件夹，选择「属性」，切换到「共享」选项卡&lt;/li&gt;
&lt;li&gt;点击「共享」按钮，在下拉菜单中选择要授权的用户（推荐选择当前登录的Windows本地账户，或选择&lt;code&gt;Everyone&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;点击「添加」，将用户加入列表后，将权限级别设置为「读取/写入」&lt;/li&gt;
&lt;li&gt;点击「共享」完成基础配置，记录下系统提示的共享地址&lt;/li&gt;
&lt;li&gt;回到属性面板，点击「高级共享」，勾选「共享此文件夹」，设置简洁的共享名（无空格、特殊字符）&lt;/li&gt;
&lt;li&gt;点击「权限」按钮，添加授权用户，勾选「完全控制」「更改」「读取」权限，点击应用保存&lt;/li&gt;
&lt;li&gt;切换到「安全」选项卡，确认授权用户已在列表中，且拥有对应的读写权限，全部设置完成后点击确定保存&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;三、iPhone Files端连接配置&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;打开iPhone自带的「文件」App，点击右上角的「···」图标，选择「连接服务器」&lt;/li&gt;
&lt;li&gt;在服务器地址栏，输入&lt;code&gt;smb://&lt;/code&gt;+你固定好的Windows电脑IP地址（例如&lt;code&gt;smb://192.168.1.100&lt;/code&gt;），点击「连接」&lt;/li&gt;
&lt;li&gt;连接方式选择「注册用户」，输入Windows电脑的本地账户&lt;strong&gt;用户名&lt;/strong&gt;和&lt;strong&gt;登录密码&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;勾选「在钥匙串中保存此密码」，避免后续重复输入，点击「下一步」&lt;/li&gt;
&lt;li&gt;连接成功后，共享文件夹会出现在「文件」App的「共享」列表中，可直接进行文件的查看、传输、编辑等操作&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;四、常见问题排查&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;报错「Socket is not connected」&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;优先检查电脑IP地址是否变动，确认当前IP与连接地址一致&lt;/li&gt;
&lt;li&gt;检查Windows的Server服务是否正常运行，防火墙是否放行共享&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;连接提示权限不足&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;确认共享文件夹的「共享」和「安全」两个选项卡中，都已给登录用户配置了读写权限&lt;/li&gt;
&lt;li&gt;优先使用Windows本地账户登录，避免Microsoft在线账户的权限校验问题&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;找不到服务器/连接超时&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;确认iPhone和Windows电脑处于同一个Wi-Fi网络，无AP隔离等路由器限制&lt;/li&gt;
&lt;li&gt;关闭电脑的VPN、代理软件，避免局域网路由异常&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item></channel></rss>