<?xml version="1.0" encoding="UTF-8"?><rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>kifroom</title>
    <link>https://www.kifroom.icu/</link>
    <description><![CDATA[kif自留地]]></description>
    <language>zh-CN</language>
    <managingEditor>kif101001000@163.com (kif)</managingEditor>
    <pubDate>Thu, 14 May 2026 13:38:28 +0000</pubDate>
    <lastBuildDate>Thu, 14 May 2026 13:38:28 +0000</lastBuildDate>
    <generator>grtblog vlocal</generator>
    <image>
      <url>https://www.kifroom.icu/uploads/pictures/2026-05-09-08:38:05-c0.jpeg</url>
      <title>kifroom</title>
      <link>https://www.kifroom.icu/</link>
    </image>
    <atom:link href="https://www.kifroom.icu/feed" rel="self" type="application/rss+xml"/><item>
      <title>写在25岁</title>
      <link>https://www.kifroom.icu/moments/2026/05/14/25years</link>
      <description><![CDATA[<blockquote><p>该内容由 RSS 渲染生成，最佳阅读体验请前往：<a href="https://www.kifroom.icu/moments/2026/05/14/25years">https://www.kifroom.icu/moments/2026/05/14/25years</a></p></blockquote><p>25岁是个很有意思的节点——它卡在“青年”和“真正的大人”之间，不上不下。我不是一个善于表达的人，但近来渐渐注意到一些东西，开始觉得需要记下来。</p>
<p>25 = 四分之一世纪。当你的生命开始以“世纪”为计量单位，那种“渺沧海之一粟”突然变得具体起来，还挺沉的。再把25年拆开看：完全空白的婴儿期、模糊的小学、开始有记忆锚点的青春期，然后突然加速到大学和工作——时间感是完全不均匀的，越往后越快。</p>
<p>25岁最残酷的真相之一，是体检报告上开始出现“异常”了。
<img src="https://tangkang.oss-cn-beijing.aliyuncs.com/mdfile/image-20260514213638509.png" alt="体检"></p>
<p>明明觉得自己还是小孩，但肩膀会痛，血脂敢偏高，视力下降，医生开始说“年轻也要注意”。朋友圈还在发徒步露营的照片，办公室柜子里已经堆起了药。
<img src="https://tangkang.oss-cn-beijing.aliyuncs.com/mdfile/image-20260514213650034.png" alt="药箱">
这种身体上的背叛感，今年第一次真切地感受到。</p>
<p>朋友圈也在今年第一次出现大规模“分化”。有人结婚二胎了，有人还在读博，有人创业一年换了三个赛道，有人彻底失联了。我们从“好朋友”变成了“不同世界的人”。和很好的朋友之间，不是没话说了，而是不知道从哪里说起。</p>
<p>能请朋友吃饭了，能买得起小时候想要的游戏机了——但没有时间玩了。月底算账时才发现，自由和窘迫是一起来的。25岁的独立，往往是一半自由、一半硬撑。</p>
<p>也有没变的，APEX依旧是喜欢的游戏，下班还是会和伙伴们玩玩游戏，周末还是会和朋友们上山。
<img src="https://tangkang.oss-cn-beijing.aliyuncs.com/mdfile/image-20260514213700079.png" alt="apex"></p>
<p><img src="https://tangkang.oss-cn-beijing.aliyuncs.com/mdfile/image-20260514213707567.png" alt="徒步"></p>
<p>至于10年前的2016年——还没用微信，每天在QQ空间发好几条从葫芦侠三楼搬的说说，配两张模糊的动漫图。大部分没人评论，偶尔有几个点赞。
<img src="https://tangkang.oss-cn-beijing.aliyuncs.com/mdfile/image-20260514213809434.png" alt="image-20260514213809434">长大后越看越尴尬，前段时间想删，太多了，不了了之。现在看只觉得可笑。不过也就这样了。</p>
<p>往年生日倒是在做点像样的事，前年回来在没充电的火车上敲了一篇长长的生日记录，最后写了一句：「成年后要养的第一个孩子是自己。」</p>
<p>两年过去了。那个孩子还活着，负债没还清，但也没饿死。理想主义小人还在耳边叨叨，只是声音比以前小了一点——不是认输了，是学会了跟他讨价还价。当时还写了一句：「世间的一切都可以努力，唯独相爱全凭运气。」现在看，好像还是这样。</p>
<p>说不上有什么答案。只是发现——人不是慢慢变成大人的，而是某天突然意识到，自己已经站在那个当年以为很远的地方了。</p>
<p><img src="https://tangkang.oss-cn-beijing.aliyuncs.com/mdfile/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20260514214249_213_223.jpg" alt="20260418-喜峰口"></p>]]></description>
      <author>kif</author>
      <guid>moment-17</guid>
      <pubDate>Thu, 14 May 2026 13:38:28 +0000</pubDate>
    </item>
    <item>
      <title>books</title>
      <link>https://www.kifroom.icu/books</link>
      <description><![CDATA[<blockquote><p>该内容由 RSS 渲染生成，最佳阅读体验请前往：<a href="https://www.kifroom.icu/books">https://www.kifroom.icu/books</a></p></blockquote><hr>
<h2>系统建立日期: 2026-05-13
总计: 7本
已读完: 3本
在读中: 3本
弃读: 1本</h2>
<h1>📚 阅读总览</h1>
<blockquote>
<p>汇总所有书籍阅读记录，持续更新。</p>
</blockquote>
<h2>📊 统计概览</h2>
<ul>
<li><strong>总书目</strong>：7 本</li>
<li><strong>已读完</strong>：3 本（43%）</li>
<li><strong>在读中</strong>：3 本（43%）</li>
<li><strong>弃读</strong>：1 本（14%）</li>
<li><strong>五星好评</strong>：3 本</li>
<li><strong>最后更新</strong>：2026-05-13</li>
</ul>
<hr>
<h2>📖 在读书籍</h2>
<blockquote>
<p>当前正同时推进三本，风格跨度大——从西方马克思主义经典到中国革命理论再到清史通俗读物，形成了一个有趣的读写场域。</p>
</blockquote>
<h3>社科/文化研究</h3>
<ol>
<li><strong>[[漫长的革命]]</strong> — [英] 雷蒙德·威廉斯 · 上海人民出版社 2022
<blockquote>
<p>与《毛选》对照阅读中。文化革命与政治革命的双重视角。当前进度：第二章。</p>
</blockquote>
</li>
</ol>
<h3>政治/历史/哲学</h3>
<ol>
<li><strong>[[毛泽东选集 第一卷]]</strong> — 毛泽东 · 人民出版社 1991
<blockquote>
<p>由《中国社会各阶级的分析》读到《中国革命战争的战略问题》。当前进度：P116。</p>
</blockquote>
</li>
</ol>
<h3>历史/非虚构</h3>
<ol>
<li><strong>[[正说清朝十二帝]]</strong> — 阎崇年 · 中华书局 2004
<blockquote>
<p>百家讲坛讲稿整理，以清十二帝生平为主线。当前进度：约 40%，读到康熙部分。</p>
</blockquote>
</li>
</ol>
<hr>
<h2>✅ 已读完</h2>
<h3>⭐⭐⭐⭐⭐ 五星经典</h3>
<ol>
<li>
<p><strong>[[活着]]</strong> — 余华 · 作家出版社 2012</p>
<blockquote>
<p>福贵的一生，关于苦难与坚韧的生命史诗。豆瓣 9.4。读完久久不能平静的那种书——人是为了活着本身而活着，而不是为了活着之外的任何事物。</p>
</blockquote>
</li>
<li>
<p><strong>[[平凡的世界]]</strong> — 路遥 · 北京十月文艺出版社 2013（全三册）</p>
<blockquote>
<p>百万字史诗，茅盾文学奖。孙少安与孙少平两兄弟在时代洪流中的奋斗与挣扎。全景式展现 1975-1985 年中国城乡社会变迁。</p>
</blockquote>
</li>
<li>
<p><strong>[[白鹿原]]</strong> — 陈忠实 · 人民文学出版社 2012</p>
<blockquote>
<p>&quot;一个民族的秘史&quot;。茅盾文学奖。白鹿两大家族三代恩怨，浓缩了从清末到新中国的历史变迁。白嘉轩的腰杆，鹿子霖的精明，朱先生的智慧——每个人物都立得住。</p>
</blockquote>
</li>
</ol>
<hr>
<h2>⚠️ 未完成</h2>
<ol>
<li><strong>[[百年孤独]]</strong> — [哥伦比亚] 加西亚·马尔克斯（范晔译）· 南海出版公司 2011
<blockquote>
<p>魔幻现实主义经典。读了开头部分，因复杂的人物关系和重复的名字中断。待重拾。</p>
</blockquote>
</li>
</ol>
<hr>
<h2>🏆 特别推荐</h2>
<h3>必读经典</h3>
<ol>
<li><strong>活着</strong> — 余华 — 生命的韧性与尊严，中国人的苦难哲学</li>
<li><strong>平凡的世界</strong> — 路遥 — 奋斗者的史诗，无论什么年龄段翻开都能被触动</li>
<li><strong>白鹿原</strong> — 陈忠实 — 读懂中国农村，就读懂了半个中国近代史</li>
</ol>
<h3>正在读的有意思对照</h3>
<ol>
<li><strong>漫长的革命 × 毛泽东选集</strong> — 西方文化马克思主义 vs 中国革命实践，对&quot;革命&quot;这个概念的跨时空对话。威廉斯谈文化变革的长时段进程，毛泽东谈阶级革命和战争规律，两者放在一起读，常有意外的火花。</li>
</ol>
<hr>
<h2>🔗 快速导航</h2>
<ul>
<li>[[60-Entertainment/Books/README|查看书籍README]]</li>
<li>[[60-Entertainment/README|返回娱乐记录主页]]</li>
</ul>
<hr>
<blockquote>
<p>💡 点击书名可跳转到详细阅读笔记</p>
</blockquote>
<p>#读书记录 #阅读总览 #个人档案</p>]]></description>
      <guid>page-10</guid>
      <pubDate>Wed, 13 May 2026 07:16:16 +0000</pubDate>
    </item>
    <item>
      <title>那些被我们「误读」的古语，其实不是误读</title>
      <link>https://www.kifroom.icu/moments/2026/05/09/misread-ancient-sayings</link>
      <description><![CDATA[<blockquote><p>该内容由 RSS 渲染生成，最佳阅读体验请前往：<a href="https://www.kifroom.icu/moments/2026/05/09/misread-ancient-sayings">https://www.kifroom.icu/moments/2026/05/09/misread-ancient-sayings</a></p></blockquote><p>「贫贱夫妻百事哀」——你大概听过这句话，也大概用它来感叹过钱对婚姻的重要性。</p>
<p>但元稹写这首诗的时候，根本不是这个意思。他在悼念亡妻，说的是「曾经和你一起过穷日子的那些回忆，如今想起来反而更让人难过」。重点不是贫贱，是失去之后回忆的痛。</p>
<p>这句话从一段悼念亲人的情感叙述，变成了一个经济决定论的婚姻结论。变化之大，几乎完全反转了原文的情感指向。</p>
<p>类似的故事也在「人不为己，天诛地灭」身上重演。</p>
<p>在原文里，「为己」的意思是修养自己、完善自己。人如果不修身、不自律，就很难在社会上立足。这是一条修身原则。</p>
<p>但在今天的语境里，它变成了「人不自私就会吃亏」。一条修身原则，被直接改写成了生存策略。</p>
<p>还有一个更隐蔽的例子：「相濡以沫」。</p>
<p>庄子讲这个故事，后面的半句才是重点——「不如相忘于江湖」。在庄子的逻辑里，两条鱼互相吐口水维持生存是悲哀的，真正的解脱是回到广阔的江湖中，各自自由地活着。所以庄子的原意是讽刺这种困境中的互相依存，鼓励人追求更大的自由。</p>
<p>但今天你听到「相濡以沫」，多半是在婚礼致辞上，用来赞美夫妻共度患难的爱情。从「放下」变成了「坚持」，几乎是反着来的。</p>
<p>类似的情况太多了：「父母在，不远游」后面还有「游必有方」；「酒肉穿肠过，佛祖心中留」后面还有「世人若学我，如同进魔道」。但互联网只传播前半截。</p>
<p>为什么会出现这种情况？</p>
<p>三个原因。</p>
<p>第一，现代传播天然偏好结论化的表达。社交媒体、评论区、短视频，都需要那种拿起来就能用的话——简短、直接、看起来像一条真理。复杂的上下文在传播中被自动压缩了。</p>
<p>第二，当代生活节奏太快，人们需要古语为现实行为提供合理性。婚姻遇到问题？「贫贱夫妻百事哀」帮你解释。职场吃亏了？「人不为己天诛地灭」帮你合理化。古语在这里的功能变了——它不再帮你理解世界，而是帮你证明自己的选择是对的。</p>
<p>第三，古语本身高度凝练，没有明确的背景说明。脱离了原文的语境之后，语义天然就有可塑性，谁都能往里面填自己的理解。</p>
<p>写到这里，我发现自己其实不太想用「误读」这个词来概括这一切。因为「误读」听起来像一个错误，好像只要翻开原典就能纠正。</p>
<p>但事情没那么简单。</p>
<p>当一个古语在当代语境里获得了全新的、自洽的含义体系，它其实就在经历一次语义重构——和语言本身的自然演化没有区别。今天的「相濡以沫」在婚礼上被用来赞美患难与共，虽然违背了庄子，但它已经长出了自己的生命。</p>
<p>真正需要警惕的不是「用错了」，而是把这个被重构过的版本当成「天然正确的现实规则」。</p>
<p>理解古语的价值，不在于用它来证明现实是正确的。而在于还原它曾经试图表达的、那些复杂的人性经验。</p>
<p>因为它们真正提供给我们的，不是答案，而是观察处境的方式。</p>]]></description>
      <author>kif</author>
      <guid>moment-16</guid>
      <pubDate>Sat, 09 May 2026 08:10:43 +0000</pubDate>
    </item>
    <item>
      <title>当整个世界都以市场、资本逻辑运行时，上世纪曾盛行的一切阶级的，种族的立场都“消失...</title>
      <link>https://www.kifroom.icu/thinkings#thinking-2</link>
      <description><![CDATA[<blockquote><p>该内容由 RSS 渲染生成，最佳阅读体验请前往：<a href="https://www.kifroom.icu/thinkings#thinking-2">https://www.kifroom.icu/thinkings#thinking-2</a></p></blockquote><p>当整个世界都以市场、资本逻辑运行时，上世纪曾盛行的一切阶级的，种族的立场都“消失”了，只留下一个对资本运行相对无害的性别议题被大谈特谈。网络加剧了这一现象，两性被信息茧房隔绝，在自己的世界着印证对方有多么不堪。部分男性失去了无产阶级意识退回“安全”的封建主义的洞穴中，部分女性在资本主义意识形态下对女性的物化和利己叙事的陷阱中挣扎。他们攻击她们的自私，她们攻击他们的腐朽，她/他们都没注意到，这背后的实质是一样的。</p>]]></description>
      <author>kif</author>
      <guid>thinking-2</guid>
      <pubDate>Sat, 09 May 2026 07:54:48 +0000</pubDate>
    </item>
    <item>
      <title>Hermes + Obsidian + GrtBlog：构建个人知识管理与自动化发布系统</title>
      <link>https://www.kifroom.icu/posts/hermes-obsidian-grtblog-knowledge-management</link>
      <description><![CDATA[<blockquote><p>该内容由 RSS 渲染生成，最佳阅读体验请前往：<a href="https://www.kifroom.icu/posts/hermes-obsidian-grtblog-knowledge-management">https://www.kifroom.icu/posts/hermes-obsidian-grtblog-knowledge-management</a></p></blockquote><h1>Hermes + Obsidian + GrtBlog：构建个人知识管理与自动化发布系统</h1>
<h2>概述</h2>
<p>在数字化时代，个人知识管理变得越来越重要。本文介绍通过整合 <strong>Hermes Agent（AI 助手）</strong>、<strong>Obsidian（知识库）</strong> 和 <strong>GrtBlog（博客系统）</strong>，构建一个无缝的自动化工作流。本文同时也是使用这套系统完成的首篇技术文章。</p>
<blockquote>
<p><strong>历史背景</strong>：旧版系统使用 OpenClaw AI 助手（2026-04-01），现已升级为 Hermes Agent。</p>
</blockquote>
<h2>系统架构</h2>
<h3>三大组件</h3>
<pre><code class="language-mermaid">graph LR
    O[Obsidian 知识库] --&gt; H[Hermes Agent]
    H --&gt; G[GrtBlog 博客]
    H --&gt; GH[GitHub 备份]
    G --&gt; ISR[ISR 静态渲染]
</code></pre>
<table>
<thead>
<tr>
<th>组件</th>
<th>角色</th>
<th>技术栈</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Obsidian</strong></td>
<td>个人知识库</td>
<td>Markdown + 十进制分类</td>
</tr>
<tr>
<td><strong>Hermes Agent</strong></td>
<td>AI 自动化引擎</td>
<td>Python + 技能系统</td>
</tr>
<tr>
<td><strong>GrtBlog</strong></td>
<td>博客发布平台</td>
<td>Go + Fiber + PostgreSQL</td>
</tr>
<tr>
<td><strong>GitHub</strong></td>
<td>版本控制 + 备份</td>
<td>git + gh-proxy</td>
</tr>
</tbody>
</table>
<h3>工作流程</h3>
<pre><code>Obsidian 写作 → Hermes 处理 → GrtBlog 发布 → GitHub 同步
    ↓               ↓              ↓              ↓
 本地知识库    AI整理/内容生成   线上博客       版本备份
</code></pre>
<h2>实施细节</h2>
<h3>1. Obsidian 知识库配置</h3>
<h4>目录结构（混合式 PARA + 十进制）</h4>
<pre><code>00-Dashboard/      # 仪表板
01-Daily/          # 每日记录
10-Tech/           # 技术笔记（本文所在位置）
11-Frontend/       # 前端技术
12-Backend/        # 后端技术
13-AI/             # AI 相关
20-Projects/       # 项目跟踪（含 GrtBlog 配置）
31-Product-Ideas/  # 产品想法
40-Knowledge/      # 通识知识
41-Concepts/       # 概念解析
50-Content/        # 内容创作
51-Blog-Drafts/    # 博客草稿
52-Tutorials/      # 教程
60-Entertainment/  # 娱乐记录
90-Archive/        # 归档
</code></pre>
<h4>知识库位置</h4>
<pre><code>~/kif-obsidian/
├── .git/ → https://github.com/wkif/kif-obsidian (代理: gh-proxy.com)
├── 01-Daily/      # 日记
├── 10-Tech/       # 技术文章
└── 20-Projects/   # 项目文档
</code></pre>
<h4>Git 配置</h4>
<pre><code class="language-bash"># 因 GFW 限制，远程仓库通过 gh-proxy.com 代理访问
git remote -v
# origin  https://gh-proxy.com/https://github.com/wkif/kif-obsidian.git

git config user.name  &quot;Kif&quot;
git config user.email &quot;wkif@users.noreply.github.com&quot;
</code></pre>
<h3>2. Hermes Agent AI 自动化引擎</h3>
<p><a href="https://hermes-agent.nousresearch.com">Hermes Agent</a> 是一个开源 AI 代理框架，支持多平台接入。</p>
<h4>当前配置</h4>
<table>
<thead>
<tr>
<th>项目</th>
<th>值</th>
</tr>
</thead>
<tbody>
<tr>
<td>模型</td>
<td>deepseek-v4-flash</td>
</tr>
<tr>
<td>提供商</td>
<td>deepseek</td>
</tr>
<tr>
<td>接入平台</td>
<td>Feishu（飞书）</td>
</tr>
<tr>
<td>工作模式</td>
<td>CLI / Feishu 对话</td>
</tr>
</tbody>
</table>
<h4>核心能力</h4>
<ul>
<li><strong>自然语言交互</strong> — 通过飞书对话直接下达指令</li>
<li><strong>知识库读写</strong> — 直接操作 Obsidian vault 文件</li>
<li><strong>API 集成</strong> — 调用 GrtBlog REST API 发布内容</li>
<li><strong>批量处理</strong> — 自动化脚本执行</li>
<li><strong>日记记录</strong> — 对话内容自动归档到 Obsidian 日记</li>
<li><strong>长期记忆</strong> — 跨会话保持用户偏好和项目上下文</li>
</ul>
<h3>3. GrtBlog 博客系统</h3>
<p>GrtBlog 是一个现代化博客系统，使用 Go + Fiber + PostgreSQL 构建。</p>
<h4>部署信息</h4>
<table>
<thead>
<tr>
<th>项目</th>
<th>值</th>
</tr>
</thead>
<tbody>
<tr>
<td>源码位置</td>
<td><code>/opt/grtblog</code></td>
</tr>
<tr>
<td>技术栈</td>
<td>Go 1.24+, Fiber, GORM, PostgreSQL 17, Redis 7</td>
</tr>
<tr>
<td>前台</td>
<td>SvelteKit + Tailwind CSS</td>
</tr>
<tr>
<td>后台</td>
<td>Vue 3 + Naive UI</td>
</tr>
<tr>
<td>博客地址</td>
<td><a href="https://www.kifroom.icu">https://www.kifroom.icu</a></td>
</tr>
<tr>
<td>API 基础</td>
<td><a href="https://www.kifroom.icu/api/v2">https://www.kifroom.icu/api/v2</a></td>
</tr>
</tbody>
</table>
<h4>核心特性</h4>
<ul>
<li><strong>ISR 静态渲染</strong> — 文章变更后自动生成静态 HTML</li>
<li><strong>WebSocket 热更新</strong> — 修改内容后读者无需刷新</li>
<li><strong>ActivityPub 兼容</strong> — 支持 Mastodon 等 Fediverse 关注</li>
<li><strong>管理后台</strong> — Vue 3 面板，支持 Markdown 实时预览</li>
</ul>
<h4>API 接口速查</h4>
<pre><code class="language-bash"># 认证
POST /api/v2/auth/login      # {credential, password} → JWT token

# 文章
POST   /api/v2/articles               # 创建文章（需 JWT）
PUT    /api/v2/articles/:id           # 更新文章（需 JWT）
DELETE /api/v2/articles/:id           # 删除文章（需 JWT）
GET    /api/v2/articles               # 公开文章列表
GET    /api/v2/articles/:id           # 公开文章详情
GET    /api/v2/admin/articles         # 管理端文章列表（需 JWT）

# 手记 (Moments)
POST   /api/v2/moments                # 创建手记

# 分类/标签/分区
POST   /api/v2/admin/categories       # 创建分类
POST   /api/v2/admin/tags             # 创建标签
POST   /api/v2/admin/columns          # 创建手记分区
</code></pre>
<h4>创建文章请求体</h4>
<pre><code class="language-json">{
  &quot;title&quot;: &quot;文章标题&quot;,
  &quot;content&quot;: &quot;Markdown 内容&quot;,
  &quot;summary&quot;: &quot;摘要（可选）&quot;,
  &quot;categoryId&quot;: 1,
  &quot;tagIds&quot;: [1, 2],
  &quot;shortUrl&quot;: &quot;article-slug&quot;,
  &quot;isPublished&quot;: true,
  &quot;isOriginal&quot;: true,
  &quot;createdAt&quot;: &quot;2024-01-24T16:07:50Z&quot;
}
</code></pre>
<blockquote>
<p>⚠️ <strong>重要</strong>：<code>PUT /articles/:id</code> 更新时必须携带 <code>isPublished: true</code>，否则会因 Go 零值默认变为草稿。</p>
</blockquote>
<h4>分类列表（2026-05-09 当前）</h4>
<table>
<thead>
<tr>
<th style="text-align:center">ID</th>
<th>分类</th>
<th style="text-align:center">文章数</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">1</td>
<td>学习笔记</td>
<td style="text-align:center">29</td>
</tr>
<tr>
<td style="text-align:center">12</td>
<td>教程</td>
<td style="text-align:center">14</td>
</tr>
<tr>
<td style="text-align:center">9</td>
<td>开发笔记</td>
<td style="text-align:center">5</td>
</tr>
<tr>
<td style="text-align:center">5</td>
<td>前端</td>
<td style="text-align:center">4</td>
</tr>
<tr>
<td style="text-align:center">2</td>
<td>Bug记录</td>
<td style="text-align:center">3</td>
</tr>
<tr>
<td style="text-align:center">8</td>
<td>工具</td>
<td style="text-align:center">2</td>
</tr>
<tr>
<td style="text-align:center">...</td>
<td>共 17 个分类</td>
<td style="text-align:center"></td>
</tr>
</tbody>
</table>
<h2>实战：旧博客批量迁移</h2>
<p>2026-05-09 完成了从旧博客 <code>wkif/kifroomnuxt3</code> 到 GrtBlog 的完整迁移：</p>
<h3>迁移数据</h3>
<table>
<thead>
<tr>
<th>项目</th>
<th style="text-align:center">数量</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>文章</strong></td>
<td style="text-align:center">82 篇</td>
</tr>
<tr>
<td><strong>手记（生活记录）</strong></td>
<td style="text-align:center">10 篇</td>
</tr>
<tr>
<td><strong>分类</strong></td>
<td style="text-align:center">17 个</td>
</tr>
<tr>
<td><strong>标签</strong></td>
<td style="text-align:center">70 个</td>
</tr>
<tr>
<td><strong>时间跨度</strong></td>
<td style="text-align:center">2020-06 ~ 2025-01</td>
</tr>
</tbody>
</table>
<h3>迁移流程</h3>
<ol>
<li><strong>克隆旧仓库</strong> → 读取 <code>content/blog/</code> 和 <code>content/life/</code> 下的 Markdown 文件</li>
<li><strong>解析 YAML frontmatter</strong> → 提取 title, date, categories, tags, isActive, cover</li>
<li><strong>建立分类/标签体系</strong> → 自动创建 GrtBlog 分类和标签</li>
<li><strong>发布文章</strong> → 通过 POST /articles 逐篇发布，严格保留原始发布日期</li>
<li><strong>清理短链接</strong> → 将含中文的 shortUrl 替换为纯英文 slug</li>
<li><strong>发布手记</strong> → 生活类内容通过 POST /moments 发布到&quot;生活&quot;分区</li>
</ol>
<h3>踩坑记录</h3>
<ol>
<li><strong>PUT 更新不可遗漏 isPublished</strong> — Go 结构体的 bool 字段零值为 false，不传该字段会导致文章自动变为草稿</li>
<li><strong>中文 shortUrl 无法访问</strong> — 部分文件名含中文，导致短链接无法解析，需清理为纯 ASCII</li>
<li><strong>占位内容覆盖原文</strong> — 测试时传入 <code>&quot;content&quot;: &quot;dummy&quot;</code> 后未及时恢复，导致 61 篇文章内容丢失，后从原文件重新恢复</li>
</ol>
<h2>日常工作流</h2>
<h3>场景 1：写日记</h3>
<pre><code>&quot;把今天的内容记到 obsidian 日记里&quot;
→ Hermes 读取对话 → 写入 01-Daily/YYYY-MM-DD.md → git push
</code></pre>
<h3>场景 2：发布博客文章</h3>
<pre><code>&quot;把这篇文章发到博客&quot;
→ Hermes 读取 Markdown → 调用 POST /articles → 文章上线
</code></pre>
<h3>场景 3：批量迁移</h3>
<pre><code>&quot;把旧博客的文章迁移到新博客&quot;
→ Hermes 克隆旧仓库 → 解析 frontmatter → API 逐篇发布
</code></pre>
<h3>场景 4：知识记录</h3>
<pre><code>&quot;学习某个技术，记到笔记里&quot;
→ Hermes 整理信息 → 写入 10-Tech/ 对应目录 → git push
</code></pre>
<h2>技术栈总结</h2>
<table>
<thead>
<tr>
<th style="text-align:left">层</th>
<th>技术</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><strong>AI 层</strong></td>
<td>Hermes Agent（deepseek-v4-flash）</td>
</tr>
<tr>
<td style="text-align:left"><strong>知识层</strong></td>
<td>Obsidian + Markdown + Git</td>
</tr>
<tr>
<td style="text-align:left"><strong>发布层</strong></td>
<td>GrtBlog（Go + Fiber + PostgreSQL + SvelteKit）</td>
</tr>
<tr>
<td style="text-align:left"><strong>存储层</strong></td>
<td>GitHub（gh-proxy.com 代理）</td>
</tr>
<tr>
<td style="text-align:left"><strong>接入层</strong></td>
<td>Feishu（飞书）</td>
</tr>
<tr>
<td style="text-align:left"><strong>自动化</strong></td>
<td>cron + Hermes 技能系统</td>
</tr>
</tbody>
</table>
<h2>总结</h2>
<p>通过整合 Hermes Agent、Obsidian 和 GrtBlog，我们构建了一个完整的个人知识管理与发布系统。核心价值：</p>
<ul>
<li>🚀 <strong>效率</strong> — 对话即管理，AI 自动完成分类、发布、备份</li>
<li>📚 <strong>积累</strong> — 所有知识有序存储，双重 Git 备份</li>
<li>🔄 <strong>迭代</strong> — 可随时更新和重新发布历史文章</li>
<li>🛡️ <strong>安全</strong> — Obsidian 纯本地文件 + GitHub 远程备份</li>
</ul>
<p><strong>技术栈</strong>：</p>
<ul>
<li>AI 引擎：Hermes Agent</li>
<li>知识库：Obsidian (Markdown)</li>
<li>博客：GrtBlog (Go + Fiber + REST API)</li>
<li>存储：Git + GitHub</li>
</ul>
<hr>
<p><em>本文是使用 Hermes Agent + Obsidian + GrtBlog 系统创建的首篇技术文章，2026-05-09 同日完成了旧博客 92 篇历史内容的完整迁移。</em></p>
<p><em>作者：kif</em>
<em>分类：技术</em>
<em>标签：hermes-agent, obsidian, grtblog, automation, knowledge-management</em></p>]]></description>
      <author>kif</author>
      <guid>article-84</guid>
      <pubDate>Sat, 09 May 2026 07:42:48 +0000</pubDate>
    </item>
    <item>
      <title>about-site</title>
      <link>https://www.kifroom.icu/about-site</link>
      <description><![CDATA[<blockquote><p>该内容由 RSS 渲染生成，最佳阅读体验请前往：<a href="https://www.kifroom.icu/about-site">https://www.kifroom.icu/about-site</a></p></blockquote>]]></description>
      <guid>page-9</guid>
      <pubDate>Sat, 09 May 2026 07:29:30 +0000</pubDate>
    </item>
    <item>
      <title>about</title>
      <link>https://www.kifroom.icu/about</link>
      <description><![CDATA[<blockquote><p>该内容由 RSS 渲染生成，最佳阅读体验请前往：<a href="https://www.kifroom.icu/about">https://www.kifroom.icu/about</a></p></blockquote><!-- raw HTML omitted -->
<!-- raw HTML omitted -->
<!-- raw HTML omitted -->
<h1>Work/Study Experience</h1>
<ul>
<li>2019-2023        XTU                                                      Network Engineering</li>
<li>2022-2023        Daoyi (Changsha) Information Technology Co. LTD.         Frontend Intern</li>
<li>2023-2024.12.31  Beijing Yunda Digital Media Technology Co. LTD.          Frontend Intern</li>
<li>2025.01.06-Now   Beijing Fenbi Future Technology Co. LTD.                 Frontend Intern</li>
</ul>
<h1>About Me</h1>
<ul>
<li>📖 Blog: <!-- raw HTML omitted -->kifroom<!-- raw HTML omitted --></li>
<li>📧 Email: <a href="mailto:kif101001000@163.com">kif101001000@163.com</a></li>
<li>💬 WeChat: rm-rf_kif</li>
<li>🌐 Focus: Vue &amp; Web Development</li>
<li>🔨 Identity: Programming Enthusiast</li>
<li>🎮 Hobby: Magic Lover</li>
<li>🍖 Preference: Meat Lover</li>
</ul>
<h1>My Cat</h1>
<!-- raw HTML omitted -->
<h1>GitHub Statistics</h1>
<p><img src="https://kifimg.oss-cn-beijing.aliyuncs.com/project/github-user-contribution.svg" alt=""></p>
<!-- raw HTML omitted -->
<pre><code class="language-txt">No activity tracked
</code></pre>
<!-- raw HTML omitted -->
<h1>Achievements</h1>
<!-- raw HTML omitted -->
<!-- raw HTML omitted -->]]></description>
      <guid>page-8</guid>
      <pubDate>Sat, 09 May 2026 07:29:13 +0000</pubDate>
    </item>
    <item>
      <title>“经济独立带来人格独立”在现实中有一定合理性，因为经济独立确实能减少对他人的依赖...</title>
      <link>https://www.kifroom.icu/thinkings#thinking-3</link>
      <description><![CDATA[<blockquote><p>该内容由 RSS 渲染生成，最佳阅读体验请前往：<a href="https://www.kifroom.icu/thinkings#thinking-3">https://www.kifroom.icu/thinkings#thinking-3</a></p></blockquote><p>“经济独立带来人格独立”在现实中有一定合理性，因为经济独立确实能减少对他人的依赖，从而增加选择权与行动自由，使人更有底气坚持自己的判断；但它并不等同于人格独立，因为人格独立的核心是自我认知、价值判断和情绪与关系中的边界感，这些不会随着收入增长自动获得。更准确地说，经济独立是人格独立的重要基础，但真正的人格独立来自于对自己负责的能力与稳定的内在判断力。</p>]]></description>
      <author>kif</author>
      <guid>thinking-3</guid>
      <pubDate>Thu, 16 Apr 2026 07:58:57 +0000</pubDate>
    </item>
    <item>
      <title>诉诸众人谬误：大家都做的事，就一定对吗？</title>
      <link>https://www.kifroom.icu/moments/2026/03/31/appeal-to-popularity</link>
      <description><![CDATA[<blockquote><p>该内容由 RSS 渲染生成，最佳阅读体验请前往：<a href="https://www.kifroom.icu/moments/2026/03/31/appeal-to-popularity">https://www.kifroom.icu/moments/2026/03/31/appeal-to-popularity</a></p></blockquote><h1>诉诸众人谬误：大家都做的事，就一定对吗？</h1>
<blockquote>
<p>从众不等于正确。真理不是通过投票产生的。</p>
</blockquote>
<p>&quot;xx也这样啊。&quot;
&quot;大家都这么做。&quot;
&quot;这是行业惯例。&quot;
&quot;别人也没说什么。&quot;</p>
<p>这几句话你一定不陌生。它们背后藏着一个非常普遍的思维陷阱——<strong>诉诸众人谬误</strong>：把&quot;很多人都这么做&quot;当成&quot;这么做没问题&quot;的理由。</p>
<h2>为什么这是错的？</h2>
<p>这个推理的逻辑非常简单：前提是&quot;很多人都做X&quot;，结论是&quot;所以X是对的&quot;。</p>
<p>问题出在前提和结论之间缺乏必然联系。<strong>行为是否普遍，不能证明行为是否正确。</strong> 很多错误恰恰因为被大多数人重复，才变得看似正常。往前推几十年，很多当时被当作&quot;常识&quot;的事，后来都被证明是错的。</p>
<p>而且这种说法还有一个隐蔽的坏处：它在转移焦点。当你用&quot;别人也这样&quot;来回应问题时，你其实不是在讨论问题本身，而是在通过举出他人的类似行为来弱化责任或抵抗改变。</p>
<h2>生活中到处是这种陷阱</h2>
<p>技术圈最典型。&quot;大家都用jQuery，为什么要学React？&quot;——这个问题看似合理，但其实应该问的是：现代前端框架能解决什么jQuery解决不了的问题？</p>
<p>工作场景也是如此。&quot;其他团队也加班，咱们加班很正常&quot;——这句话在回避一个更关键的问题：我们的效率能不能提高？能不能不加班？</p>
<p>生活中更是常见。&quot;大家都闯红灯，我闯一次没事&quot;——这里面的风险逻辑完全被&quot;从众心理&quot;覆盖了。</p>
<p>注意到没有？这些说法有一个共同点：<strong>它们都在阻止你思考更好的方式。</strong></p>
<h2>怎么识别和应对？</h2>
<p>关键信号词其实很明显：&quot;大家都……&quot;&quot;别人也……&quot;&quot;xx也这样&quot;&quot;这是惯例&quot;&quot;行业标准&quot;&quot;普遍做法&quot;。</p>
<p>听到这些词的时候，你心里就要亮起红灯：对方是不是在用&quot;别人的行为&quot;代替&quot;论证的理由&quot;？</p>
<p>应对的方式也很简单，把讨论拉回正题就行。</p>
<p>可以这样说：&quot;别人怎么做不重要，重要的是这件事本身合不合理？有没有更好的做法？我们的具体情况是什么？&quot;</p>
<p>也可以质疑&quot;众人&quot;的真实性：&quot;真的是所有人吗？有没有幸存者偏差？成功的案例有没有被忽略？&quot;</p>
<p>或者直接探索替代方案：&quot;有没有反例？有没有人尝试过不同的做法？其他领域是怎么解决类似问题的？&quot;</p>
<h2>为什么我们容易掉进这个陷阱？</h2>
<p>从心理学角度看，做和别人一样的事能带来安全感。出错了责任是分散的——&quot;法不责众&quot;的心态根深蒂固。</p>
<p>从认知角度看，独立思考需要更多精力，跟随多数是省力的选择。大脑天生喜欢走捷径。</p>
<p>从社会角度看，害怕与众不同是一种深层的本能。我们害怕被孤立、被批评。</p>
<p>从信息角度看，我们往往不知道&quot;众人&quot;背后的真实情况。看到的只是表面现象。</p>
<h2>一个简单的思维习惯</h2>
<p>每次听到&quot;大家都这样&quot;的时候，先别急着接受，试着停下来想一想：<strong>&quot;大家都这样&quot;和&quot;这样做是对的&quot;之间，真的画等号吗？</strong></p>
<p>历史上无数的进步，恰恰都是因为有人没有跟随&quot;大家&quot;。从哥白尼到伽利略，从女性投票权到种族平等，每一个进步在它发生之前，&quot;大家&quot;都不觉得有问题。</p>
<p><strong>真理不是通过投票产生的。对的事就算只有一个人在做，它依然是对的。</strong></p>
<p>下次再听到&quot;大家都这么做&quot;的时候，不妨多问一句：那又怎样？</p>
<hr>
<p><em>首发于 kifroom.icu · 写于 2026-03-31</em></p>]]></description>
      <author>kif</author>
      <guid>moment-14</guid>
      <pubDate>Tue, 31 Mar 2026 00:00:00 +0000</pubDate>
    </item>
    <item>
      <title>“理中客”的污名化：中立立场的消亡</title>
      <link>https://www.kifroom.icu/moments/2026/03/31/demonization-of-rationality</link>
      <description><![CDATA[<blockquote><p>该内容由 RSS 渲染生成，最佳阅读体验请前往：<a href="https://www.kifroom.icu/moments/2026/03/31/demonization-of-rationality">https://www.kifroom.icu/moments/2026/03/31/demonization-of-rationality</a></p></blockquote><h1>&quot;理中客&quot;的污名化：中立立场的消亡</h1>
<blockquote>
<p>真正理性的表达，不是回避判断，也不是机械中立，而是在明确责任的前提下，仍然愿意承认现实的复杂性。</p>
</blockquote>
<p>你有没有发现，&quot;理中客&quot;这个词的意思已经彻底变了？</p>
<p>十几年前，说一个人&quot;理性、中立、客观&quot;是一种赞赏。现在你说谁是&quot;理中客&quot;，基本等于在骂人——虚伪、逃避、和稀泥、不敢站队。</p>
<p>一个词从褒义变成攻击性标签，这背后藏着这几年公共讨论环境的某种深刻变化。</p>
<hr>
<h2>&quot;理中客&quot;是怎么变味的</h2>
<p>这个词的演变大致经历了三个阶段。</p>
<p>最早是<strong>自我标榜期</strong>。那时候人们说&quot;我是一个理中客&quot;，意思是我不盲目站队、我重视证据、我避免情绪化判断。社会对它的认知是正面的。</p>
<p>然后是<strong>滥用与质疑期</strong>。问题开始显现——有些人机械地说&quot;双方都有问题&quot;，在责任明确的时候回避价值判断，用&quot;中立&quot;来掩盖逃避。&quot;不能只听一面之词&quot;（在证据确凿时）、&quot;真相还不清楚&quot;（在事实明显时）——这些说法越来越多，人们开始怀疑：他到底是真中立还是装中立？</p>
<p>到了现在这个阶段，它彻底变成了<strong>攻击性标签</strong>。&quot;又来一个理中客&quot;&quot;典型的理中客思维&quot;——没人再用它来自我介绍，它只用来否定别人。中间立场变得可疑，理性讨论的空间被挤压缩小，所有人都被推着选边站队。</p>
<h2>为什么中立越来越难？</h2>
<h3>阵营化的舆论结构</h3>
<p>过去讨论一个问题，大概是&quot;观点A ← 中间地带 → 观点B&quot;这样的结构。双方在中间地带交流、碰撞、互相修正。</p>
<p>现在的结构变成了&quot;阵营A ←← 中立者 →→ 阵营B&quot;。中立者被夹在中间，两边都挨打。阵营的逻辑很简单：&quot;不支持我 = 支持对方&quot;。中立被认为立场不清，立场不清就是可疑。</p>
<p>于是你必须在两分钟之内选边站，否则两边都会攻击你。</p>
<h3>标签比论证高效太多了</h3>
<p>理性反驳需要阅读、思考、组织论据，十分钟起步。贴标签只需要一秒钟，零思考，零风险，传播还快。</p>
<p>&quot;又一个理中客&quot;——五个字，情绪到位、立场明确、群体认同、快速传播、瞬间终结讨论。相比之下，任何试图理性分析的长文都显得笨重而不合时宜。在快节奏的信息环境里，<strong>高效率的沟通方式淘汰了低效率的</strong>，不管它有没有道理。</p>
<h3>算法也在推波助澜</h3>
<p>社交平台的算法奖励什么？立场鲜明、情绪强烈、简单直接、符合阵营预期。这些内容互动高、传播快、曝光大。</p>
<p>惩罚什么？立场复杂、分析细致、承认矛盾、不符合任何阵营。这些内容互动低、被忽视、甚至被攻击。</p>
<p>中立者处境很尴尬：在阵营A的信息流里，他偏向B；在阵营B的信息流里，他偏向A。两边都不讨好。</p>
<h3>伪中立败坏了真中立的声誉</h3>
<p>不是所有&quot;中立&quot;都是真的。</p>
<p>真中立是基于事实和证据，承认现实复杂性，不回避必要的价值判断。伪中立是回避事实，机械地强调&quot;双方都有问题&quot;，在责任明确时装糊涂。</p>
<p>伪中立的存在污染了整个中立立场的声誉。劣币驱逐良币，最后所有中立都被怀疑。</p>
<h2>真中立和伪中立怎么区分？</h2>
<p>其实标准很简单。真正的中立者会提供具体数据，承认论证的局限性，在原则问题上有立场，该追责时追责、分清主次责任。</p>
<p>伪中立者则相反：在事实明确时说&quot;需要更多证据&quot;，在责任对等时说&quot;双方都有问题&quot;，无限提高证据标准来拖延判断，用&quot;复杂&quot;作为不判断的借口。</p>
<p>一个最简单的测试：<strong>去掉&quot;中立&quot;这层包装，看他的观点是否还有实质内容。</strong> 如果只剩下&quot;我两边都不得罪&quot;的空话，那大概率是伪中立。</p>
<h2>保持理性能做什么？</h2>
<p>我真不觉得现在这个环境下保持中立是一件容易的事。你会被误解、被攻击、被两边抛弃。</p>
<p>但某种意义上，中间地带的存在本身就是有价值的。当所有人都在情绪化地选边站队时，愿意说&quot;这件事比表面看起来复杂&quot;的人，反而显得珍贵。</p>
<p>不需要每件事都表达立场。不需要每个热点都参与讨论。不需要被所有人喜欢。</p>
<p><strong>真正理性的表达，不是回避判断，也不是机械中立，而是在明确责任的前提下，仍然愿意承认现实的复杂性。</strong></p>
<p>警惕的不是&quot;理中客&quot;这个词本身，而是当公共讨论越来越依赖标签而不是分析时，复杂问题就很难被真正理解。</p>
<p>而这种能力——在情绪洪流中保持清醒，在阵营压力下独立思考——在当下的舆论环境中，反而变得越来越稀缺了。</p>
<hr>
<p><em>首发于 kifroom.icu · 写于 2026-03-31</em></p>]]></description>
      <author>kif</author>
      <guid>moment-13</guid>
      <pubDate>Tue, 31 Mar 2026 00:00:00 +0000</pubDate>
    </item>
    <item>
      <title>严肃议题的互联网梗化现象</title>
      <link>https://www.kifroom.icu/moments/2026/03/31/memeification-of-serious-topics</link>
      <description><![CDATA[<blockquote><p>该内容由 RSS 渲染生成，最佳阅读体验请前往：<a href="https://www.kifroom.icu/moments/2026/03/31/memeification-of-serious-topics">https://www.kifroom.icu/moments/2026/03/31/memeification-of-serious-topics</a></p></blockquote><h1>严肃议题的互联网梗化现象</h1>
<blockquote>
<p>互联网并不会自动让世界变得更理性，相反，它往往会把复杂世界压缩成一个&quot;低分辨率&quot;的版本。</p>
</blockquote>
<p>你有没有发现一个奇怪的现象：越是严肃的社会议题，一旦进入互联网，往往会被迅速简化成一个梗、一张图、一句话。复杂的经济问题变成&quot;都去送外卖了&quot;，深刻的教育困境变成&quot;内卷&quot;两个字，国际关系变成各种政治段子。</p>
<p>这不是偶然。背后有六股力量在共同推动这个趋势。</p>
<hr>
<h2>注意力经济的残酷逻辑</h2>
<p>严肃内容天然处于劣势。它信息复杂、理解成本高、需要深度思考。而梗简单直观、情绪强烈、秒级反馈。算法不关心什么更重要，它只关心什么更容易被传播。</p>
<p>一个真实案例：一篇关于就业结构性矛盾的深度分析，可能只有几千阅读。而它被浓缩成&quot;年轻人找不到工作，都去送外卖了&quot;这个梗之后，可以获得百万传播。前者需要你花二十分钟理解，后者一秒钟就让你产生了&quot;我懂了&quot;的错觉。</p>
<h2>情绪永远跑在理性前面</h2>
<p>&quot;根据统计局数据，16-24岁失业率是X%&quot;——这条信息需要验证、需要理解统计口径、情绪调动几乎为零。</p>
<p>&quot;年轻人找不到工作，国家在干什么！&quot;——这条不需要任何验证，瞬间引发愤怒或共鸣。</p>
<p>情绪天然比理性更容易扩散。这不是谁的错，这是人类大脑的出厂设置。</p>
<p>一个典型的演变路径是：<strong>严肃议题 → 情绪激发 → 简化表达 → 梗化传播 → 娱乐消费。</strong></p>
<p>环境问题就是一个很好的例子。从&quot;气候变化的系统性应对&quot;，一路演变成&quot;地球要完蛋了→都是资本家的错→地球不需要人类&quot;的表情包。人们好像讨论了什么，又好像什么都没讨论。</p>
<h2>符号正在替代表达</h2>
<p>现实对话中，你可以花三十分钟慢慢解释一个观点，有语气、有肢体语言、可以即时澄清对方误解。</p>
<p>互联网上，你只有一百四十个字，或者一张图。</p>
<p>于是观点变成了立场，立场变成了标签，标签变成了符号，符号变成了梗。每一次压缩都在丢失信息，但每一次压缩都在提升传播力。</p>
<p>疫情初期的讨论就是典型。原本需要讨论的是&quot;如何平衡防疫强度和社会成本&quot;——这涉及医疗资源、经济影响、风险评估等多个维度。但互联网上很快就变成了&quot;清零派 vs 躺平派&quot;的对立。任何具体建议都会被贴上标签，理性讨论的空间几乎消失。</p>
<p>这就是信息压缩的代价：<strong>压缩率越高，传播力越强，但失真也越严重。</strong> 当压缩率达到99%的时候，就只剩情绪和立场了，真正的问题早已消失。</p>
<h2>幽默背后的心理防线</h2>
<p>面对严肃议题——战争、灾难、社会冲突——人本能地感到恐惧和无力。互联网放大了人的一种防御机制：<strong>幽默化。</strong></p>
<p>疫情时期的梗文化就是典型。表面上大家在&quot;居家办公真爽&quot;&quot;核酸排队交友&quot;，背后其实是一种焦虑的集体释放。幽默帮我们缓解了恐惧，在失控中找到了掌控感。</p>
<p>但代价也很清楚：严肃性被消解了，真实困境被遮蔽了，问题讨论变成了娱乐消费。</p>
<h2>平台想要什么，你就看到什么</h2>
<p>社交平台的核心目标不是提供完整信息，而是留住你的时间。</p>
<p>算法优化的指标是点击率、停留时长、互动率、广告收入。什么内容最有效？制造冲突、激发情绪、简单直观、让人站队。深度分析互动低，理性讨论传播慢。</p>
<p>这是一个自我强化的循环：你看到情绪化内容→情绪反应导致点击互动→算法觉得这招好用→推送更多类似内容→你的习惯被培养→严肃内容更难生存。最终形成信息茧房、情绪极化、认知简化。</p>
<h2>那我们该怎么办？</h2>
<p>面对一个热点，我给自己总结了一套判断标准：</p>
<p>看到它的时候，我是情绪强烈但说不太清楚为什么，还是能跟人讲明白来龙去脉？我想立刻转发吐槽，还是想了解更多？我愿不愿意听不同观点，还是只想表达立场？</p>
<p>几个有用的策略：</p>
<p><strong>24小时缓冲期。</strong> 看到热点，等一天再发表观点。情绪冷却了，信息补充了，很多冲动发言自然就不想发了。</p>
<p><strong>主动找&quot;反梗&quot;。</strong> 每次看到一个梗，刻意去找完整的报道、专业的分析、不同的观点。不要只看符合自己想法的内容。</p>
<p><strong>质疑极端表达。</strong> 看到&quot;都是XX的错&quot;的时候，问一句：真的&quot;都是&quot;吗？还有没有其他因素？证据在哪里？</p>
<p><strong>追问&quot;然后呢&quot;。</strong> 知道这个梗，然后呢？能解决什么问题？我能做什么？</p>
<hr>
<p>互联网让世界更快了，但不一定更好。我们能看到的更多了，但未必理解得更深。</p>
<p><strong>保持清醒，需要刻意的努力。</strong></p>
<p>不是现实变简单了，而是我们看到的版本被简化了。梗很有趣，但现实更复杂。情绪很痛快，但思考更重要。</p>
<p>问自己一个问题：这个内容让我更理解现实，还是更远离现实？</p>
<p>如果你的答案是后者，也许是时候放下手机，去读一篇长文章了。</p>
<hr>
<p><em>首发于 kifroom.icu · 写于 2026-03-31</em></p>]]></description>
      <author>kif</author>
      <guid>moment-12</guid>
      <pubDate>Tue, 31 Mar 2026 00:00:00 +0000</pubDate>
    </item>
    <item>
      <title>身份替代论证：重要的不是你是谁，而是你说的对不对</title>
      <link>https://www.kifroom.icu/moments/2026/03/31/identity-as-argument</link>
      <description><![CDATA[<blockquote><p>该内容由 RSS 渲染生成，最佳阅读体验请前往：<a href="https://www.kifroom.icu/moments/2026/03/31/identity-as-argument">https://www.kifroom.icu/moments/2026/03/31/identity-as-argument</a></p></blockquote><h1>身份替代论证：重要的不是你是谁，而是你说的对不对</h1>
<blockquote>
<p>真正有力量的不是&quot;我属于哪个群体&quot;，而是&quot;我能拿出什么事实和逻辑&quot;。</p>
</blockquote>
<p>&quot;作为程序员，我觉得……&quot;
&quot;作为打工人，公司应该……&quot;
&quot;作为女性，我们都认为……&quot;
&quot;作为父母，我坚决反对……&quot;</p>
<p>这些表达方式你一定很熟悉。用身份来开头，好像没什么问题。但仔细想想就会发现：<strong>当身份标签开始替代论证本身的时候，讨论的质量就在悄悄下降。</strong></p>
<h2>身份标签为什么会成为武器？</h2>
<p>用身份开头，其实有很多心理动机。</p>
<p>它可以增强说服力。&quot;我认为996不合理&quot;和&quot;作为程序员，我认为996不合理&quot;，后者听起来更有分量，因为它把自己的观点包装成了群体声音。</p>
<p>它可以提供心理安全感。当你说&quot;我们&quot;而不是&quot;我&quot;的时候，你就不再是独自面对质疑了。你背后有整个群体。</p>
<p>它也是防御机制。如果对方质疑你的观点，你可以说&quot;你是在攻击我们整个群体&quot;——这一招在阻止讨论方面极其有效。</p>
<h2>什么时候是合理使用，什么时候是滥用？</h2>
<p>判断标准其实很简单：<strong>去掉身份标签，你的论据还站不站得住？</strong></p>
<p>如果去掉&quot;作为程序员&quot;之后，你还有具体的数据、逻辑和事实来支撑你的观点，那身份只是背景信息。如果你去掉身份标签之后，剩下的话毫无说服力，那身份就被当成了论据本身。</p>
<p>举个例子：</p>
<p><strong>合理使用。</strong> &quot;作为做过三年前端的人，我遇到过这个坑：当用户量超过10万时，这种写法会导致内存溢出。我的解决方案是……&quot;——这里的身份只是说明经验的来源，核心是具体的技术场景和解决方案。</p>
<p><strong>滥用。</strong> &quot;作为资深程序员，我觉得Vue比React好。你们没做过大项目，不懂。&quot;——没有具体论据，没有技术对比，只有一个身份标签在那里压人。</p>
<p>前者是&quot;提供视角&quot;，后者是&quot;终止讨论&quot;。</p>
<p>同样，在工作讨论中，&quot;作为一线员工，我观察到新流程执行时平均每单多花5分钟&quot;——这是有价值的信息。而&quot;作为打工人，公司就应该给我们涨薪。你不同意就是资本家走狗&quot;——这是在用身份制造对立，而不是在讨论涨薪的理由。</p>
<h2>身份防御是最隐蔽的讨论终结者</h2>
<p>最值得警惕的，是身份被用作防御武器时的效果。</p>
<p>正常的讨论应该是这样：你提出一个观点 → 对方质疑 → 你用更多论据回应 → 讨论深入。</p>
<p>当身份介入之后的变形：你提出一个观点 → 对方质疑 → 你说&quot;你在攻击我的身份&quot; → 对方被迫自证清白 → 原来的问题被丢到一边。</p>
<p>&quot;我不是程序员，但我觉得……&quot;
&quot;你又不是程序员，你不懂。&quot;</p>
<p>——这句&quot;你不是XX你不懂&quot;几乎是万能的讨论终止器。它绕过了所有论证，直接从身份上否定对方的发言资格。</p>
<h2>怎么避免成为这种讨论的受害者？</h2>
<p>如果你在表达，记住一个原则：<strong>身份是背景，不是论据。</strong> 使用身份标签的时候，确保后面跟着的是具体的事实、数据和逻辑，而不是一句空泛的判断。</p>
<p>如果你在回应别人的身份化表达，最好的方式不是指责对方&quot;你在诉诸身份&quot;，而是把讨论拉回到事实层面：<strong>&quot;感谢分享你的视角。能不能具体说说，你遇到了什么情况？有什么数据支持这个观点？&quot;</strong></p>
<p>这样既尊重了对方的身份视角，又把讨论引导到了更实质的方向。</p>
<h2>一个不那么政治正确的观察</h2>
<p>这几年身份政治越来越盛行，每个人都被贴上各种标签。这些标签有时候能帮助我们快速理解一个人的立场和视角，但更多时候，它让我们停止了思考。</p>
<p>当我们看到一个人的言论时，第一反应变成了&quot;他是哪个阵营的&quot;而不是&quot;他说了什么&quot;。当我们反驳一个人的时候，第一反应变成了挖他的身份背景而不是批驳他的逻辑。</p>
<p>这其实是一种思维的懒惰。身份标签让我们不用费力去理解复杂论点，不用面对不舒服的质疑，不用承认&quot;对方可能有道理&quot;的可能性。</p>
<hr>
<p><strong>记住：当我们讨论问题时，重要的不是&quot;我是谁&quot;，而是&quot;我说的对不对&quot;。</strong></p>
<p><strong>身份是背景，不是论据。</strong>
<strong>经验是补充，不是全部。</strong>
<strong>真正有力量的，始终是事实和逻辑。</strong></p>
<p>下次你听到&quot;作为XX，我觉得……&quot;的时候，不妨先忽略前面四个字，直接看后面的内容有没有道理。也下次你想用&quot;作为XX&quot;开头的时候，问问自己：去掉这个标签，我的话还站得住吗？</p>
<hr>
<p><em>首发于 kifroom.icu · 写于 2026-03-31</em></p>]]></description>
      <author>kif</author>
      <guid>moment-15</guid>
      <pubDate>Tue, 31 Mar 2026 00:00:00 +0000</pubDate>
    </item>
    <item>
      <title>职场中的马基阿维利主义：不是教你变坏，而是教你别天真</title>
      <link>https://www.kifroom.icu/moments/2026/03/31/machiavellianism-in-workplace</link>
      <description><![CDATA[<blockquote><p>该内容由 RSS 渲染生成，最佳阅读体验请前往：<a href="https://www.kifroom.icu/moments/2026/03/31/machiavellianism-in-workplace">https://www.kifroom.icu/moments/2026/03/31/machiavellianism-in-workplace</a></p></blockquote><h1>职场中的马基阿维利主义：不是教你变坏，而是教你别天真</h1>
<blockquote>
<p>真正成熟的职场思维，不是变得更阴险，而是变得更清醒</p>
</blockquote>
<p>工作几年后，你会发现一个有点残酷的事实：那些在职场上走得最远的人，往往不是最勤奋的，也不是最聪明的——而是最清醒的。</p>
<p>这不是一篇教你&quot;变坏&quot;的文章。恰恰相反，我想聊的是：如何在看清规则的前提下，依然保持自己的底线。</p>
<hr>
<h2>先聊清楚一个误解</h2>
<p>提到&quot;马基阿维利主义&quot;，很多人第一反应是阴险、算计、不择手段。但说实话，这种理解太表面了。</p>
<p>真正的马基阿维利主义，往本质了说，其实就是三件事：<strong>对规则的深刻理解、对人性的现实判断、对机会的精准把握</strong>。</p>
<p>它不是问&quot;要不要成为一个马基阿维利主义者&quot;，而是问一个更实在的问题：<strong>当你身处一个充满博弈的环境，你是选择天真地捂上眼睛，还是选择清醒地应对？</strong></p>
<hr>
<h2>那些你以为的&quot;不公平&quot;，其实只是你不懂规则</h2>
<h3>1. 关系不是原罪，不懂关系才是</h3>
<p>我见过太多新人，抱着&quot;只要把工作做好就够了&quot;的心态埋头苦干。一年后绩效不错，但晋升给了那个能力相当、却更&quot;会来事&quot;的同事。于是愤愤不平：凭什么？</p>
<p>其实换个角度想就明白了：职场从来就不是一个只看结果的封闭考场。它是一个开放的协作网络，<strong>你的价值不光取决于你做了什么，还取决于谁知道你做了什么</strong>。</p>
<p>那个&quot;会来事&quot;的同事，可能只是比你多做了几件小事：</p>
<ul>
<li>主动了解公司的权力结构，知道谁才是真正的决策者</li>
<li>适度参与跨部门项目，让更多人看到他的能力</li>
<li>在技术分享会上展示专业水准</li>
<li>和mentor保持良好的互动关系</li>
</ul>
<p>这不是虚伪，也不是拍马屁。这是理解了&quot;可见性&quot;这件事需要主动创造。如果他只会社交、没有真本事，反而会更快失去信任。</p>
<p><strong>关系的健康边界其实很简单：如果一段关系建立在互相创造价值的基础上，它就是健康的；如果建立在单方面欺骗和利用上，它迟早会反噬。</strong></p>
<h3>2. 信息本身就是一种权力</h3>
<p>一个很残酷但真实的道理：在职场中，信息就是权力。</p>
<p>什么时候该说话、说多少、怎么说——这些看似琐碎的选择，其实决定了你在信息食物链中的位置。</p>
<p>我总结过信息管理的三个维度，很值得想一想：</p>
<p><strong>何时表达？</strong> 在什么场合说、在谁面前说、时机是否合适，这些问题比&quot;说什么&quot;本身更重要。</p>
<p><strong>表达多少？</strong> 透露多少信息、保留多少，本质上是在控制信息的流动方向。</p>
<p><strong>如何表达？</strong> 用什么语言风格、强调什么方面、规避什么风险——同一个事实，不同的表达方式会产生完全不同的效果。</p>
<p>懂得信息管理的人，往往比单纯努力的人走得更远。这不是教你隐瞒，而是教你<strong>策略性地沟通</strong>。</p>
<p>说一个很具体的技巧：同样是汇报工作——</p>
<p>普通表达是&quot;我完成了这个项目&quot;；
策略表达是&quot;我在X时间内完成了Y项目，节省了Z成本，得到了客户的积极反馈&quot;。</p>
<p>同一个事实，后者让成果变得可量化、可感知。这不是吹牛，这是让你的劳动果实被人看见。</p>
<h3>3. 结果导向不等于不择手段</h3>
<p>理想主义者说：&quot;我应该做什么？什么是对的？&quot;
现实主义者说：&quot;什么最有效？在这个环境下如何达成目标？&quot;</p>
<p>我不是说理想主义不好。但纯粹的理想主义在职场上往往碰得头破血流，因为<strong>职场不是一个&quot;努力就有回报&quot;的理想场，它是一个竞争与博弈的现实系统</strong>。</p>
<p>举个例子：项目出了问题。</p>
<p>A类人想的是&quot;我们怎么解决这个问题&quot;，然后分析原因、寻找方案、向上汇报进展。
B类人想的是&quot;怎么避免责任落到我头上&quot;，然后收集证据证明不是自己的错。</p>
<p>表面上B类人更&quot;聪明&quot;，短期内保护了自己。但长期来看，A类人建立了&quot;解决问题的人&quot;这个声誉，而B类人逐渐失去了所有人的信任。</p>
<p><strong>正确的结果导向，不是&quot;为了赢不择手段&quot;，而是&quot;在底线内高效地达成目标&quot;。</strong></p>
<hr>
<h2>最大的风险不是输，而是失去底线</h2>
<p>职场的本质不是一次性博弈，而是长期重复博弈。在这个系统里，<strong>口碑永远大于一两次的胜利，信任永远大于一时的得失。</strong></p>
<p>信任这东西很有意思：</p>
<ul>
<li>建立起来很慢，需要一次又一次地兑现承诺</li>
<li>但脆弱得可怕，一次失信就可能崩塌</li>
<li>然而一旦建立，它带来的复利效应是巨大的</li>
</ul>
<p>有信任的人，会有更多的合作机会、更低的沟通成本、更强的影响力、更好的资源。</p>
<p>失去信任的人呢？被孤立、被质疑、被边缘化，最终职业发展撞上天花板。</p>
<p>所以守住底线不是一种道德说教，而是一种<strong>理性的长期策略</strong>。哪些底线值得守？</p>
<p>诚实——可以策略性表达，但不能撒谎。
守信——可以谨慎承诺，但承诺了就要做到。
不伤害——可以竞争，但不能恶意害人。
专业——可以包装，但必须有真材实料。
担当——可以保护自己，但不能全是甩锅。</p>
<hr>
<h2>防御性马基阿维利主义：不是变坏，而是别天真</h2>
<p>前面说了这么多，其实可以归结为一句话：<strong>不是教你变坏，而是教你别天真。</strong></p>
<p>&quot;防御性马基阿维利主义&quot;不是让你去算计别人，而是让你在被算计的时候能识别出来、能保护自己。</p>
<h3>先判断你处在什么环境</h3>
<p>如果你所处的环境，经常出现以下情况：</p>
<ul>
<li>功劳被抢是常事</li>
<li>黑锅有人往你身上甩</li>
<li>表面一团和气，背后各怀心思</li>
<li>信息经常被故意隐瞒或扭曲</li>
<li>小团体和派系分明</li>
<li>老实人总是吃亏</li>
<li>&quot;会做人&quot;比&quot;会做事&quot;更重要</li>
</ul>
<p>如果超过五项，那你大概率处在一个高度马基阿维利的环境中。在这种情况下，天真就是对自己最大的不负责任。</p>
<h3>五项防御能力</h3>
<p><strong>信息敏感度。</strong> 不要对所有人都完全透明。重要决策前先了解利益相关方，文字记录重要沟通，识别谁在收集信息、为了什么目的。</p>
<p><strong>功劳保护。</strong> 在邮件中明确自己的贡献，在会议上适度展示工作，对关键决策和成果做好记录。不是炫耀，而是让你的付出有迹可循。</p>
<p><strong>责任界定。</strong> 协作时明确分工，问题出现时先理清事实再讨论责任。不主动背锅，但该担当时也不推诿。</p>
<p><strong>人际判断。</strong> 观察谁真正可信、谁只是表面友好。注意谁在困难时支持你、谁只在顺境时靠近你。对不同的人保持不同程度的信任。</p>
<p><strong>权力地图。</strong> 理解组织的真实权力结构——不只看职位，还要看谁能影响决策、资源往哪个方向流动。</p>
<h3>守住底线的第三条路</h3>
<p>很多人以为只有两个选择：要么天真被欺负，要么变坏去算计。</p>
<p>其实有第三条路——</p>
<p><strong>保持善意，但不天真。</strong>
<strong>坚持原则，但理解现实。</strong>
<strong>真诚待人，但有防御能力。</strong>
<strong>追求公平，但不期待完美。</strong>
<strong>相信规则，但知道规则如何被绕开。</strong></p>
<hr>
<h2>四种职场人格，你在哪一阶段？</h2>
<p>我见过四种人：</p>
<p><strong>天真型</strong>——相信努力就够了，不懂规则。执行力强，但容易被利用。做得累，升不上去。</p>
<p><strong>马基阿维利型</strong>——不择手段，利益至上。短期获利快，但长期失去信任，最终孤立。</p>
<p><strong>玩世不恭型</strong>——看透了一切，但选择消极应对。安全，但平庸。</p>
<p><strong>清醒成熟型</strong>——理解规则、保持底线、有策略。既能保护自己，又能持续发展。</p>
<p>很多人从天真相，碰壁后要么走向马基阿维利型，要么滑向玩世不恭型。但真正理想的路径是：<strong>天真 → 受挫 → 学习 → 清醒成熟。</strong> 在受挫后不是走向另一个极端，而是找到一个成熟的平衡点。</p>
<hr>
<h2>你该怎么办？</h2>
<p>不同阶段有不同的侧重：</p>
<p><strong>刚入行的头两年</strong>，核心是建立专业能力、理解游戏规则。多做事、多观察、少评论。</p>
<p><strong>2到5年的成长期</strong>，重点是扩大影响力、建立自己的网络。主动展示价值，积极争取机会，但注意别太aggressive树敌太多。</p>
<p><strong>五年以上的成熟阶段</strong>，就要学会平衡各方利益、培养真正的影响力。带团队，创造长期价值。</p>
<p><strong>到了管理岗</strong>，考验的是如何在组织利益和个人发展之间找到平衡点。</p>
<hr>
<h2>最后</h2>
<p>写了这么多，其实核心就三句话：</p>
<p><strong>懂得规则</strong>——理解游戏怎么玩。
<strong>理解人性</strong>——知道人会怎么做。
<strong>守住底线</strong>——记住自己是谁。</p>
<p>回到标题说的：不是教你变坏，而是教你别天真。</p>
<p>不是变得更阴险，而是变得更清醒。</p>
<p>这不是妥协，这是成熟。</p>
<blockquote>
<p>保持善意 + 但不天真
坚持原则 + 但理解现实
真诚待人 + 但有防御能力
追求公平 + 但不期待完美
相信规则 + 但知道潜规则</p>
</blockquote>
<p><strong>真正的职场智慧，不是学会算计，而是学会在保持自我的前提下，理解和应对复杂的职场环境。</strong></p>
<hr>
<p><em>首发于 kifroom.icu · 写于 2026-03-31</em></p>]]></description>
      <author>kif</author>
      <guid>moment-11</guid>
      <pubDate>Tue, 31 Mar 2026 00:00:00 +0000</pubDate>
    </item>
    <item>
      <title>缘分</title>
      <link>https://www.kifroom.icu/moments/2025/05/19/life-8</link>
      <description><![CDATA[<blockquote><p>该内容由 RSS 渲染生成，最佳阅读体验请前往：<a href="https://www.kifroom.icu/moments/2025/05/19/life-8">https://www.kifroom.icu/moments/2025/05/19/life-8</a></p></blockquote><p>“你为什么还不谈恋爱？”</p>
<p>这或许是我近两年被问过最多的问题，要怎么回答呢？</p>
<p>我见过形形色色的爱情。或许是稀里糊涂地加上微信，看你朋友圈长得不错就找你聊天顺便约出来吃个饭，稍微熟络后找个机会就告白了，一束鲜花，一些情话，一段不健康的恋爱。
也或许是异地一千多个日夜，隔着屏幕用冰冷的文字表达关心，在寒冬打着视频相互依偎取暖，好像没有什么可以阻挡这汹涌的爱意。可最后还是分开了。
这个时代的恋爱大多都是快餐，慢慢来三个字弥足珍贵到难以启齿，也有那么些刻骨铭心的爱恋，但因为种种原因不疾而终。
我记得老舍在《骆驼祥子》里写道：爱是人中龙凤才给得起的东西，真正的情种只会出生于大富之家。
多年前我万分不解，吐槽作者将爱情利益化。多年后那颗名为时光的子弹正中眉心。</p>
<p>所以让我们回到开头，该怎么回答呢？我想是因为大家都是普通人吧。
我们的外貌普通，人生普通，爱也普通。有的心向大海，怀揣小时候浪迹天涯的潇洒，不愿被世事浮沉束缚，因为他们从未认真凝视过这个世界，哪怕一秒钟；有的心比天高，眼里只能容纳前程，路上的风景都来不及欣赏，因为命运不容他们有片刻喘息，那山顶他们从未去过。还有的一部分抓着回忆不放，像是在看一部哑剧，剧里剧外都是黑白色的，没有声音没有光彩，找不到出路。
每个人心里都有不可言说的秘密，有比爱情更重的东西，又怎么坦诚去爱人。</p>
<p>我记得朋友去年第一次问我为什么不谈恋爱时。我总会打着哈哈说自己太丑了，觉得自己现在挣不够足够满足恋爱花销的金银。
但我一向是向往爱情的，在我眼中爱情始终是如白兰花一样纯洁的东西，从未变过。多年前，我遇到喜欢的姑娘恨不得告诉全世界我喜欢她，告白要轰轰烈烈，恋爱要轰轰烈烈，哪怕最后分开也要轰轰烈烈。时至今日依然如此，只是随着岁月流逝你不得不将这些疯狂以一种委婉的形式来诠释。</p>
<p>写了那么多的随笔，我差不多把身边所有的感情都写了个遍，每一次的随笔细看都在隐喻关乎‘情’这一字。每一次每个人的成长都是离不开‘情’的，无非是爱情，亲情，友情等等关于‘情’的分支不同罢了。</p>
<p>这两年身边的朋友也相互换过一批，和朋友的交心也体现了不同的参差，大多数朋友对我明面上的评价依旧是“好人”二字，更多人心里的评价在平时我玩抽象的态度中，也能管中窥豹看出一二，但有时想想人生难得糊涂，何必在意太多。</p>
<p>认真看的朋友在这一篇可能觉得语序不通，感觉像流水账，那并不是，只是未看破其中的隐喻。
总而言之，这篇随笔就两个字“缘分”</p>
<p>#树 #随记 #遐想 #源稚生.出处#源稚生 @源稚生.</p>]]></description>
      <author>kif</author>
      <guid>moment-9</guid>
      <pubDate>Mon, 19 May 2025 10:29:25 +0000</pubDate>
    </item>
    <item>
      <title>然后我开始思考，人到底能感受多少个夏天</title>
      <link>https://www.kifroom.icu/moments/2025/05/19/life-5</link>
      <description><![CDATA[<blockquote><p>该内容由 RSS 渲染生成，最佳阅读体验请前往：<a href="https://www.kifroom.icu/moments/2025/05/19/life-5">https://www.kifroom.icu/moments/2025/05/19/life-5</a></p></blockquote><blockquote>
<p>转自网友</p>
</blockquote>
<p>然后我开始思考，人到底能感受多少个夏天。#随笔</p>
<p>在午后出门</p>
<p>长夏默默，我什么话也不想说，就这样与眩晕的白昼对坐。耳机里随机到一首’绿色翻涌成夏’，内心被一种名为夏天的感受填满。</p>
<p>从十几岁开始就对夏天有特殊的情结，大概因为在整个学生时代，伴随着逐渐拉长的日色，升高的温度，夏季的到来往往指向一些重要的节点，中考，高考，毕业，成年前所有重大人生转折都发生在夏天。</p>
<p>压力和温度一并升高，晚自习的时候汗津津的胳膊会粘起试卷一角，风扇在吱呀呀搅动闷热的空气。每个人似乎都行色匆匆，在日子慢慢变长的罅隙里拼尽全力揭开一个期许已久的答案。
无处可藏的闷热逼迫着对未来毫无心理准备的我们往前走。混乱的，热烈的，彻底的，痛苦的。</p>
<p>那年夏天雨水很多，我睡觉很少，身体很强壮，但毫无防备被淋湿过很多回，有的时候是雨水，有的时候是眼泪。
现在对于十几岁的夏天已经有点记不真切，好像那些都不过是我的一场幻觉。</p>
<p>大学以后的夏天似乎乐得清闲，有很多时间用来胡思乱想。散步的时候脑袋里蹦出来一句“夏天的爱太没天赋，稍有不慎便炙烤万物。”</p>
<p>我的爱应该也同夏天一样没有天赋。一旦产生便炙烤万物，如火如荼，稍有不悦便又乌云密布，暴雨如瀑，夜过去又热烈如初。总是学不会留白，学不会细水长流，总是像未来不再来，像是没有明天的去爱，浓烈到甚至有点灼人。我对这样的感情态度深恶痛绝，但是好像很难改掉。</p>
<p>我想大概是因为夏季与我们的生命曾经真的是同一质地。</p>
<p>当然以上这些都只是虚无缥缈的东西，是旁枝末节，是午后睡醒起来越想越淡的梦。
总归还是要着眼当下，做一些具体的事，过具体的生活。人在夏天主要的任务就是过夏天，长长的散步，让风吹过裙摆和头发。然后去把该做的任务做完，让日子按部就班的行进，也让命运温柔推动自己前进。</p>
<p>自然赠予你树冠 微风 肩头的暴雨</p>
<p>片刻后生成平衡 忠诚 不息的身体</p>
<p>捕食饮水 清早眉间白云生</p>
<p>跳跃漫游 晚来拂面渤海风</p>
<p>然后我开始思考 人到底能感受多少回夏天。</p>]]></description>
      <author>kif</author>
      <guid>moment-6</guid>
      <pubDate>Mon, 19 May 2025 10:26:15 +0000</pubDate>
    </item>
    <item>
      <title>Anlin日寄</title>
      <link>https://www.kifroom.icu/moments/2025/02/03/anlin</link>
      <description><![CDATA[<blockquote><p>该内容由 RSS 渲染生成，最佳阅读体验请前往：<a href="https://www.kifroom.icu/moments/2025/02/03/anlin">https://www.kifroom.icu/moments/2025/02/03/anlin</a></p></blockquote><p>习惯一边欺骗自己准备好了接受最坏的结果，又暗自期待撞上大运惊艳所有人，但是最后什么都没发生，最坏的没来，最好的也没来，</p>
<hr>
<p>“当初给你定级 GPT4，是高于你测试时的水平的。我是希望上线后，你能够拼一把，快速成长起来的。GPT4 这个层级，不是把事情做好就可以的。你需要有体系化思考的能力。你做的事情，他的价值点在哪里？你是否作出了壁垒形成了核心竞争力？部门给了你这么好的显卡，不拿出一点不一样的成就，是无法说服大家的。”</p>
<hr>
<p>我喜欢小红书是因为上面低智又自私小资脱离实际而不自知，喜欢贴吧是因为老哥双标又伪善用别人的善良当自己作恶的挡箭牌，喜欢知乎是因为众人皆醉我独醒优越感拉满还有一堆小说软广，喜欢豆瓣是因为不管讨论什么都怪男的不行，喜欢nga是因为里边只要骂原神大家都哗哗点赞，喜欢b站是因为这边永远幼稚永远性压抑永远被带节奏，喜欢微博是因为上面一堆谣言还有成吨的饭圈，喜欢抖音是因为一堆营销号把乱七八糟的视频加上黄底黑字假装新闻发，我这种阴湿老鼠每天就靠吃这堆互联网泔水活着。</p>
<hr>
<p>“咱们的面试就到这里，还有什么问题要问吗？”“请问您怎么看待劳动法？”“我不害怕。”</p>
<hr>
<p>互联网时代每个人都是伏地魔，把灵魂分成7片放在不同的社交账号，一旦集齐七个碎片就会迎来社会性死亡。</p>
<hr>
<p>知识付费的精髓就在于，不买超过经济能力的课就觉得没用</p>
<hr>
<p>上班其实是奴隶市场从买断制改成了订阅制</p>
<hr>
<p>朋友的学校的心理咨询很神奇，好像把小学生“放心我绝对不告诉别人”的习惯带到了工作中，老师说，你们放心咨询内容肯定是保密的，于是我朋友真的跑去心理咨询，第二天他舍友很好奇地问他，你干嘛了，辅导员让我多关心下你，还叫我每天填表。他说去了学校的咨询室，舍友安慰他，你再想不开，也不至于那么想不开。听过一个离奇的说法，国内超过一半的心理咨询需求，是由性工作者承担的，剩下那部分，交给算命的。算命是一种很玄学的东西，比如说以前我妈带我去算命，算命的说这孩子能学，以后成绩会很好，后来我成绩真挺不错。</p>
<p>我觉得不行这太封建迷信了，于是大学里，我靠自己的实力逆天改命，考进了年级倒数。但是冥冥之中又有些玄学存在，填专业那天我姐嘲笑我：“以后别人有男朋友的来找你修电脑，你在那对着电脑发愁，她跟男朋友卿卿我我，修好了人家说句谢谢把你打发了，你还得意地不行，哈哈，舔狗。“彼时我意气风发，激动地反驳她这个专业不是修电脑的。没想到我低估了事情的严重性。初中同学来找我修电脑，想起我姐的话，我问她，哎你谈男朋友了吗，她说昨天刚被告白还没官宣，我说恭喜恭喜。</p>
<p>参加活动，看到旁边小哥字写得不错，就顺便加了个QQ，过了几天他找我说，哎你是计院的，能麻烦帮我弄下电脑吗，要装flash，我一边远程操作一边跟他开玩笑，你不会也有男朋友吧，他语气突然兴奋，“我靠你怎么看出来的！！你也是吗！！”</p>
<p>后来机缘巧合我靠着塔罗算命赚了一点点钱，就刚好够加两蛋挞，我买的那幅塔罗很神奇，它的封面上写了很长一段话，大致意思是“塔罗并不能预测未来，只能帮人看清当前的状况，从而做出决定。“看起来那么实诚，以至于我怀疑买了副盗版。后来我发现，原来真的是这样，借着牌这个载体，塔罗师引导客户倾诉自己的烦恼，一步一步帮客户梳理内心的想法，最后让对方作出自己的选择。比如很多人会问“我应该继续考研吗？”标准题型，</p>
<p>“你的心态有一些焦虑，可能会遇到一些困难，但可以克服，只要放平心态继续努力一定可以的。“</p>
<p>虽然只是很初步的探索，但可以看出来算命确实承担了一部分心理咨询的需要，然后我还想实际了解性工作者那部分的情况，所以托朋友帮忙介绍了一下。我交代完了警察叔叔，是在这里按手印吗，好的好的。</p>
<hr>
<p>北漂就是周六下午午睡过头之后，到外卖送达之前，被全世界遗忘的三十分钟</p>
<hr>
<p>所谓KPI，就是主人把盘子扔出去，让狗去捡，哪天狗学会了自己扔盘子，就成了OKR。</p>
<hr>
<p>我妈说进入社会要学会为人处事，所以我最近在很认真地学习这个方面，有句名言是这么说的“不要听一个人说了什么，要听他没说什么”。我一直觉得这很困难，直到今天有句话让我豁然开朗，“永远不要找一个男生要腹肌照，如果他有你早就看过了”。我举一反三列了个名单，大致有清北、185、18、年薪、颜值，以及腹肌。如果你和一个男生聊了三天以上他还没有提到这些东西,那就是没有。</p>
<hr>
<p>很多我这样的人，为了掩饰自己的差劲而活得用力过猛，尤其是在朋友圈里。要旅游要social要学习要offer，不能闲不能闲，不然在下次名为“你这周末有什么安排？”的social大竞赛的时候会因只能回一句“哎呀就宅在家里啦”而变成社交达特利，所以你才看到旅游轰趴offer图书馆打卡，同龄人大都写作闪闪发光，名为故作精彩。我想停下这参卷的手，却发现我甚至停不了手冲。</p>
<hr>
<p>小时候特别喜欢爬楼顶，有天晚上我爬上了一个即将拆迁的楼顶，满地细碎的闪光，宛如星河从天而降，在脚下肆意流淌,第二天白天去看，一地碎玻璃。所有事都是这样，远远地看着它的时候，神秘、美丽、变幻莫测，直到真正接触，才发现全是苟且。我觉得自杀这件事不会是例外，它一定也有很多无趣讨厌的地方。自杀的人才是真正的理想主义者，他们居然相信这个世界上，还有一件事会和想象中一样单纯而美好。金三银四跪得悄无声息，hr又开始喊金五银六,我好像懂了，单数月是金，双数月是银。一条规律或者道理要广为流传，它不一定多么准确多么富有逻辑，但它必须顺口。最近看了很多成功经验分享，发现了和大佬的差距,厉害的人，如果有想要的东西得不到，就会不断努力进取克服重重困难，最终达成目标，而我这种摆烂人，得不到就不想了，这一定就是别人常说的随薪锁欲。</p>
<hr>
<p>大城市的打工人有很多诡异的生存哲学，</p>
<p>比如通勤，在我们这，一般把要坐一个半小时车去上的班叫做出差。我问他坐地铁那么长时间会干点啥，他说看书，很多时候看书是一个特别好的托辞，没有人知道你看书的到底是校花的贴身高手还是献给阿尔吉侬的花束，于是他们会在心里取两者均值作为你的印象分。很多事都是这样，百分之二十高雅百分之八十低级，大多数人一边沉迷于80%的低级乐趣，一边用20%的高雅满足虚荣，比如咖啡。我继续问那通勤的时候看书有什么要注意的吗？他说你问到重点了，一定要定闹钟。我肃然起敬，赞叹道哇你看书那么专心。他说不是，看书容易睡过站。原来是20%读书80%睡眠。自从上了高中我就一直在疑惑一件事，小时候我到底为什么会不想睡午觉？工作之后的人生突然塌缩成睡觉和上班的死循环，偶尔靠熬夜喝酒抽烟换来一点个人时间。我不会抽烟，但是很多时候需要合群，在巷子里开摆的时候，别人叼根烟我叼个棒棒糖多少有点幼稚，气势上先输了一截，所以我学会了吹烟，就点根烟叼着吹，反正烟头看起来都一明一灭，于是我在别人眼里成了一个不吐烟的狠人。我在想，熬夜会折寿，就短期而言是延长了今天的时间，约等于把70岁的十年挪到20岁提前兑付，虽然不知道交换的比例是多少，但听起来好像不亏。只要不是卖给资本家。大学的寝室楼总让我联想到共享充电宝的充电箱，一排一排电池塞在里面充满四格，然后到大城市里被榨干，区别是充电宝可以重复使用，而我们除了这一生又没有别的时间，无所谓了，反正空掉的位置总有新电池补上。</p>
<hr>]]></description>
      <author>kif</author>
      <guid>moment-3</guid>
      <pubDate>Sun, 02 Feb 2025 21:35:13 +0000</pubDate>
    </item>
    <item>
      <title>狗</title>
      <link>https://www.kifroom.icu/moments/2025/02/03/life-3</link>
      <description><![CDATA[<blockquote><p>该内容由 RSS 渲染生成，最佳阅读体验请前往：<a href="https://www.kifroom.icu/moments/2025/02/03/life-3">https://www.kifroom.icu/moments/2025/02/03/life-3</a></p></blockquote><p>这狗现如今竟不咬人了。</p>
<p>它是我家对面一只一直被拴在水龙头铁管上的大黄狗。打记事起它就吠个不停，路过的人，熟人陌生人它都必须吼上两声。</p>
<p>少时暑天，经常用竹竿和竹片制成的工具去捕蜻蜓，需要新鲜的蛛网缠上边，这样的才粘，才抓得住。这家很受蜘蛛的青睐，檐下的网又结实又大张。但见到这狗我就发怵，村里的人家户我多少都去混过脸熟，它家的地盘我一次都没踏足过，因为这狗的脾气实在骇人。</p>
<p>它家一双老人，一对孙子女。我印象里，它家的这位婆婆性子也很烈，她总训斥这个孙子，大小事都骂他，每天如此；女生名字不太记得了，几乎只有寒暑假待在这块儿，开学就被接走了；那个男孩儿倒一直生活在这儿，他的父母离婚了，父亲整日酗酒难见踪影，一直由家里的老长辈抚养着，他倒也真如其名，“少强”，打小就能自己拾柴火、搓衣服。</p>
<p>后来我上了大学，对村里的八卦都鲜有耳闻了，偶尔打视频母亲会跟我唠唠家常和周遭一切的变化，谁考上了哪里，谁又二婚了......那位婆婆杵上了拐杖，男孩父亲出门务工了，女生再没来过，男生上了中学，是我以前那所学校。</p>
<p>去年寒假回到家里，村子有些肃静。为什么这样感觉，始终找不出个所以然来。熬夜的时候，老听见外面传来锁链拖拉在地上的声音，有些瘆人。兴许是谁又偷带捕猎器械来抓野猪了，为打消顾虑，我开门便瞧见这只老狗。倏地又关上门，直到现在我都害怕它，以为它挣脱了束缚终于可以到处乱咬了。隔天母亲叫我别担心，它现在谁也不咬，这家的公公患了癌，晚期，家里人都忙着照顾，男孩哆嗦着用大铁盆盥洗一大家子的衣物，他的父亲不再烂醉，帮着煮饭捯饬家务，我第一次瞧见这对老人的其他子女，他们家似乎比以往更祥和些，然母亲又讲道，原来那男孩的二叔也胃癌，时日估计比那个公公还少。</p>
<p>母亲平时会把剩菜里的肉沫星子挑出来夹到院坝乱石堆里的一块砖头上，那狗晚上会自己来寻吃的。后来的每一个晚上，夜里外面又传来锁链声，但我很是安心。</p>
<p>毕业的第一年工作失意，国庆回家偷点清闲，但头一次感觉村子里太静了，静得有些冷清。傍晚，秋雨更添凉意，它跛着来了，颈上没了铁链，也无半点恶意，我夹了几块水煮青菜里的白肉给它。顺着它来的方向望去，十余载，第一次见它家门户紧闭，灶房的烟囱也戒烟了，外面的银杏都快掉完了，蜘蛛张罗着织帘子盖住整幢老瓦房防止落尘。我没有好奇去问母亲为何，我想，在外打拼的子女把老人接走去享天伦之乐了，男孩也一定考上了县里的重点高中。</p>
<p>#随记</p>
<p>回了趟家，碰见它时，它正躺在一堆萧条了的乱草里。</p>
<p>这里是它家的坡坎下，边上这家人也养了条小黄狗。小黄的狗缘可好了，村里的狗都和它熟络，这大黄也能经常蹭上一顿饭。</p>
<p>路过的时候，我向它打招呼，它尽显晚年的从容，就那样一动不动地望着我。</p>
<p>回来的时候给它带了包狗粮，顺手拿了个杯子盛点给它送去。是不如肉来得香，还是瞧不上我呢，它吃了两粒，浅尝辄止。</p>
<p>夜里大雨骤降，我忽地想到什么。怜悯心又作祟，驱使我外出寻找。身上的衣裤愈发沉重，它平时待的地方这会哪里都没在，这狗可机灵，一定找了个好窝正睡着好觉呢，我心想。</p>
<p>隔天放晴了，母亲叫我赶紧出来，试着唤对面的它过来。它慵懒地抻个腰，然后循声朝我们望了一眼，过后便自顾自去草丛里排泄了。这老狗，真是的，我们笑了笑便回屋了。</p>
<p>就请了两天的假，当晚就得离开。临行前，父母重复叮咛，“充电器带好没，身份证记得揣好......”。我自然是收拾齐整，哪里会落下什么东西呢。走到涵洞前，和刚摘完菜路过的阿婆问了个好，正巧它闲逛完回来，阿婆讲这狗怕是撑不过这个冬天。</p>
<p>我丢三落四的毛病似是犯了，遂折返回家。</p>
<p>找来个纸箱子，里面放了些狗粮和鸭肉，我示意它过来。它踉跄着走向我，没有走进去；抬头望着我，朝蹲踞一生的地方去了。</p>
<p>我不知道于它而言何处才是归宿，它已经不起任何折腾。我收起了箱子，往里面添了杯水，放在了院坝的葡萄藤下。月光铺满无粼的池塘，折射进我的双眸，我看见十五年有余，不远处的那条生灵终其一生“忠”其一生。</p>
<p>什么是真正的解脱呢？兴许它最门儿清。它有过家，现在仍有挂念它的大家，也许它被忘记了，又好像不曾被遗忘。#狗</p>]]></description>
      <author>kif</author>
      <guid>moment-4</guid>
      <pubDate>Sun, 02 Feb 2025 21:32:41 +0000</pubDate>
    </item>
    <item>
      <title>rollup- 功能使用与插件开发</title>
      <link>https://www.kifroom.icu/posts/r_o_l_l_u_p_-_-_gong_neng_shi_yong_yu_cha_jian_kai_fa</link>
      <description><![CDATA[<blockquote><p>该内容由 RSS 渲染生成，最佳阅读体验请前往：<a href="https://www.kifroom.icu/posts/r_o_l_l_u_p_-_-_gong_neng_shi_yong_yu_cha_jian_kai_fa">https://www.kifroom.icu/posts/r_o_l_l_u_p_-_-_gong_neng_shi_yong_yu_cha_jian_kai_fa</a></p></blockquote><h2>介绍：</h2>
<p>Rollup 是一款基于 <strong>ES Module</strong> 模块规范实现的 <strong>JavaScript</strong> 打包工具，天然具有根据ES Module 的Tree Shaking 功能。</p>
<h2>打包配置</h2>
<h3>方式一：rollup.config.js 配置文件</h3>
<p>具体配置项：<a href="https://www.rollupjs.com/configuration-options/">配置选项</a></p>
<p>如 rollup.config.js:</p>
<pre><code class="language-js">const buildOptions = {
  input: [`./src/index.js`],
  output: [
    {
      file: `./dist/es/index.js`,
      format: 'esm'
    },
    {
      file: `./dist/cjs/index.js`,
      format: 'cjs'
    }
  ]
}
export default buildOptions
</code></pre>
<p>在 package.json 中加入如下的构建脚本</p>
<pre><code class="language-json">  &quot;scripts&quot;: {
    &quot;test&quot;: &quot;echo \&quot;Error: no test specified\&quot; &amp;&amp; exit 1&quot;,
    &quot;build&quot;: &quot;rollup -c&quot;
  },
</code></pre>
<p>常用配置项：</p>
<h4>多产物配置：</h4>
<pre><code class="language-js">output : [
  {
    file: `./dist/es/index.js`,
    format: 'esm'
  },
  {
    file: `./dist/cjs/index.js`,
    format: 'cjs'
  }
]
</code></pre>
<p>配置多个 output 实现导出多种打包产物。</p>
<h4>多入口配置：</h4>
<p>将 input 设置为一个数组或者一个对象:</p>
<pre><code class="language-js">  input : [`./src/index.js`,`./src/utils.js`],
</code></pre>
<p>如果不同入口对应的打包配置不一样，也可以默认导出一个配置数组</p>
<pre><code class="language-js">const indexBuildOption = {
  input: ['./src/index.js'],
  output: {
    file: `./dist/es/index.js`,
    format: 'esm'
  }
}
const utilsBuildOptions = {
  input: ['./src/utils.js'],
  output: {
    file: `./dist/es/utils.js`,
    format: 'cjs'
  }
}
export default [
  indexBuildOption,
  utilsBuildOptions
]
</code></pre>
<h4>自定义output</h4>
<pre><code class="language-js">  output: {
    // 产物输出目录
    dir: path.resolve(__dirname, 'dist'),
    // 以下三个配置项都可以使用这些占位符:
    // 1. [name]: 去除文件后缀后的文件名
    // 2. [hash]: 根据文件名和文件内容生成的 hash 值
    // 3. [format]: 产物模块格式，如 es、cjs
    // 4. [extname]: 产物后缀名(带`.`)
    // 入口模块的输出文件名
    entryFileNames: `[name].js`,
    // 非入口模块(如动态 import)的输出文件名
    chunkFileNames: 'chunk-[hash].js',
    // 静态资源文件输出文件名
    assetFileNames: 'assets/[name]-[hash][extname]',
    // 产物输出格式，包括`amd`、`cjs`、`es`、`iife`、`umd`、`system`
    format: 'cjs',
    // 是否生成 sourcemap 文件
    sourcemap: true,
    // 如果是打包出 iife/umd 格式，需要对外暴露出一个全局变量，通过 name 配置变量名
    name: 'MyBundle',
    // 全局变量声明
    globals: {
  // 项目中可以直接用`$`代替`jquery`
      jquery: '$'
    }
  },
</code></pre>
<h3>方式二：API 调用</h3>
<p>涉及到两个 api:<code>rollup.rollup</code> 和<code>rollup.watch</code>，前者实现一次性打包，后者实现对打包的监听，文件修改自动重新打包。</p>
<h4>rollup.rollup</h4>
<p>新建 build.js</p>
<pre><code class="language-js">const rollup = require('rollup')

const inputOptions = {
  input: './src/index.js',
  external: ['lodash']
}
const outputOptionList = [
  {
    dir: './dist/cjs',
    format: 'cjs',
    entryFileNames: '[name].[hash].js',
    chunkFileNames: '[name].[hash].js',
    sourcemap: true,
    globals: {
      lodash: '_'
    }
  }
]
async function build() {
  let bundle
  let buildFailed = false
  try {
    bundle = await rollup.rollup(inputOptions)
    for (const outputOption of outputOptionList) {
      const { output } = await bundle.generate(outputOption)
      await bundle.write(outputOption)
    }
  }
  catch (error) {
    buildFailed = true
  }
  if (bundle) {
    await bundle.close()
  }
  process.exit(buildFailed ? 1 : 0)
}

build()
</code></pre>
<p>output 和input 配置和上面描述一致，build 方法里面，通过rollup.rollup 方法生成 bundle 对象，拿到 bundle 对象，根据每一份输出配置，调用 generate 和 write 方法分别生成和写入产物，调用 bundle 对象的 close 方法来结束打包。</p>
<h4>rollup.watch</h4>
<pre><code class="language-js">const rollup = require('rollup')

const inputOptions = {
  input: './src/index.js',
}
const outputOptionList = [
  {
    dir: './dist/cjs',
    format: 'cjs',
    entryFileNames: '[name].[hash].js',
    chunkFileNames: '[name].[hash].js',
    sourcemap: true,
  }
]
const watcher = rollup.watch({
  input: inputOptions,
  output: outputOptionList,
  watch: {
    exclude: ['node_modules/**'],
    nclude: ['src/**'],
  }
})
watcher.on('restart', () =&gt; {
  console.log('===&gt; watch.js:28 ~ restart',)
})
watcher.on('change', (id) =&gt; {
  console.log('===&gt; watch.js:32 ~ id', id)
})
watcher.on('event', (e) =&gt; {
  if (e.code === 'BUILD_END') {
    console.log('===&gt; watch.js:35 ~ BUILD_END',)
  }
})
</code></pre>
<p>修改文件可以看到信息：</p>
<p><img src="https://kifimg.oss-cn-beijing.aliyuncs.com/img/20250115142455972.png" alt="image-20250115142453067"></p>
<h2>插件</h2>
<p>Rollup 的打包过程中，会定义一套完整的构建生命周期，从开始打包到产物输出，中途会经历一些标志性的阶段，并且在不同阶段会自动执行对应的插件钩子函数(Hook)。对Rollup 插件来讲，最重要的部分是钩子函数，一方面它定义了插件的执行逻辑，也就是&quot;做什么&quot;；另一方面也声明了插件的作用阶段，即&quot;什么时候做&quot;，这与 Rollup 本身的构建生命周期息息相关。</p>
<p>插件列表：https://github.com/rollup/awesome</p>
<h3>构建阶段</h3>
<p>主要分为<strong>Build</strong> 和<strong>Output</strong> 阶段，前者主要进行创建模块依赖图，初始化各个模块的 AST 和模块间依赖关系，</p>
<p>回到上面 build.js 文件，打印一下bundle：</p>
<pre><code class="language-js">bundle = await rollup.rollup(inputOptions)
console.log('===&gt; build.js:24 ~ bundle', JSON.stringify(bundle))
</code></pre>
<p>结果：</p>
<pre><code class="language-js">{
  cache: {
    modules: [ [Object], [Object] ],
    plugins: [Object: null prototype] {}
  },
  close: [AsyncFunction: close],
  closed: false,
  generate: [AsyncFunction: generate],
  watchFiles: [Getter],
  write: [AsyncFunction: write],
  [Symbol(nodejs.asyncDispose)]: [AsyncFunction: [nodejs.asyncDispose]]
}
</code></pre>
<p>其中cache：</p>
<p><img src="https://kifimg.oss-cn-beijing.aliyuncs.com/img/20250115143445874.png" alt="cache"></p>
<p>这个对象的作用在于存储各个模块的内容及依赖关系，同时暴露 generate 和</p>
<p>write 方法，以进入到后续的 Output 阶段（ <strong>write 和 generate 方法唯一的区别在于前者打包完产物会写入磁盘，而后者不会</strong>）</p>
<p>之后来到output 阶段：</p>
<pre><code class="language-js">const { output } = await bundle.generate(outputOption)
console.log('===&gt; build.js:28 ~ output', output)
</code></pre>
<p>结果：</p>
<pre><code class="language-js">[
  {
    exports: [],
    facadeModuleId: '/Users/kif/Desktop/code/study/rollup/src/index.js',
    isDynamicEntry: false,
    isEntry: true,
    isImplicitEntry: false,
    moduleIds: [
      '/Users/kif/Desktop/code/study/rollup/src/utils.js',
      '/Users/kif/Desktop/code/study/rollup/src/index.js'
    ],
    name: 'index',
    type: 'chunk',
    dynamicImports: [],
    fileName: 'index.ufh_8Hzm.js',
    implicitlyLoadedBefore: [],
    importedBindings: {},
    imports: [],
    modules: [Object: null prototype] {
      '/Users/kif/Desktop/code/study/rollup/src/utils.js': [Object],
      '/Users/kif/Desktop/code/study/rollup/src/index.js': [Object]
    },
    referencedFiles: [],
    code: &quot;'use strict';\n&quot; +
      '\n' +
      'const add = (a,b)=&gt;{\n' +
      '  return a + b;\n' +
      '};\n' +
      '\n' +
      '// import {merge} from &quot;lodash&quot;;\n' +
      'console.log(add(1,8));\n' +
      &quot;// console.log('===&gt; index.js:2 ~ merge', merge);\n&quot; +
      '//# sourceMappingURL=index.ufh_8Hzm.js.map\n',
    map: SourceMap {
      version: 3,
      file: 'index.ufh_8Hzm.js',
      sources: [Array],
      sourcesContent: [Array],
      names: [],
      mappings: ';;AAAA,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG;AACnB,EAAE,OAAO,CAAC,GAAG,CAAC;AACd;;ACFA;AAEA,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrB;;'
    },
    preliminaryFileName: 'index.!~{001}~.js',
    sourcemapFileName: 'index.ufh_8Hzm.js.map'
  },
  {
    fileName: 'index.ufh_8Hzm.js.map',
    name: [Getter],
    names: [],
    needsCodeReference: false,
    originalFileName: [Getter],
    originalFileNames: [],
    source: `{&quot;version&quot;:3,&quot;file&quot;:&quot;index.ufh_8Hzm.js&quot;,&quot;sources&quot;:[&quot;../../src/utils.js&quot;,&quot;../../src/index.js&quot;],&quot;sourcesContent&quot;:[&quot;const add = (a,b)=&gt;{\\n  return a + b;\\n}\\nexport default add&quot;,&quot;// import {merge} from \\&quot;lodash\\&quot;;\\nimport add from \\&quot;./utils\\&quot;;\\nconsole.log(add(1,8));\\n// console.log('===&gt; index.js:2 ~ merge', merge);\\n&quot;],&quot;names&quot;:[],&quot;mappings&quot;:&quot;;;AAAA,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG;AACnB,EAAE,OAAO,CAAC,GAAG,CAAC;AACd;;ACFA;AAEA,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrB;;&quot;}`,
    type: 'asset'
  }
]
</code></pre>
<p>生成的 output 数组即为打包完成的结果。当然，如果使用 bundle.write 会根据配置将最后的产物写入到指定的磁盘目录中。</p>
<p>对于不同的阶段，Rollup 插件会有不同的插件工作流程。</p>
<h3>插件类型</h3>
<blockquote>
<p>参考：https://www.rollupjs.com/plugin-development/#build-hooks</p>
</blockquote>
<p>插件的各种 Hook 可以根据这两个构建阶段分为两类: Build Hook 与 Output Hook。</p>
<ul>
<li>Build Hook 即在 Build 阶段执行的钩子函数，在这个阶段主要进行模块代码的转换、AST 解析以及模块依赖的解析，那么这个阶段的 Hook 对于代码的操作粒度一般为 <strong>模块</strong> 级别，也就是单文件级别。</li>
<li>Ouput Hook (官方称为 Output Generation Hook )，则主要进行代码的打包，对于代码而言，操作粒度一般为 <strong>chunk</strong> 级别(一个 chunk 通常指很多文件打包到一起的产物)。</li>
</ul>
<p>根据不同的 Hook 执行方式也会有不同的分类，主要包括 Async 异步钩子 、 Sync 同步钩子 、 Parallel 并行钩子 、 Squential 串行钩子 、 First 这五种</p>
<ul>
<li><code>async</code>：该钩子也可以返回一个解析为相同类型的值的 Promise；否则，该钩子被标记为 <code>sync</code>。</li>
<li><code>first</code>：如果有多个插件实现此钩子，则钩子按顺序运行，直到钩子返回一个不是 <code>null</code> 或 <code>undefined</code> 的值。</li>
<li><code>sequential</code>：如果有多个插件实现此钩子，则所有这些钩子将按指定的插件顺序运行。如果钩子是 <code>async</code>，则此类后续钩子将等待当前钩子解决后再运行。</li>
<li><code>parallel</code>：如果有多个插件实现此钩子，则所有这些钩子将按指定的插件顺序运行。如果钩子是 <code>async</code>，则此类后续钩子将并行运行，而不是等待当前钩子。</li>
</ul>
<h3>构建阶段</h3>
<p><img src="https://kifimg.oss-cn-beijing.aliyuncs.com/img/20250115155450544.png" alt="构建阶段"></p>
<ol>
<li>首先经历 options 钩子进行配置的转换，得到处理后的配置对象。</li>
<li>随之 Rollup 会调用 buildStart 钩子，正式开始构建流程。</li>
<li>Rollup 先进入到 resolveId 钩子中解析文件路径。(从 input 配置指定的入口文件开始)。</li>
<li>通过调用 load 钩子加载模块内容。</li>
<li>在 <a href="https://www.rollupjs.com/plugin-development/#transform"><code>load</code></a> 钩子之后，加载的 <code>code</code> 与缓存副本的代码相同，则 Rollup 将跳过模块的 <a href="https://www.rollupjs.com/plugin-development/#transform"><code>transform</code></a> 钩子。为了防止这种情况，插件可以实现<strong>shouldtransformcachedmodule</strong>钩子并返回 <code>true</code>，以丢弃缓存副本并转换模块。</li>
<li>没有击中缓存或者 <strong>shouldtransformcachedmodule</strong>返回true则调用 <strong>transform</strong> 钩子来对模块内容进行进行自定义的转换，比如 babel 转译</li>
</ol>
<h3>输出阶段</h3>
<p><img src="https://kifimg.oss-cn-beijing.aliyuncs.com/img/20250115160015239.png" alt="输出阶段"></p>]]></description>
      <author>kif</author>
      <guid>article-42</guid>
      <pubDate>Wed, 15 Jan 2025 11:41:24 +0000</pubDate>
    </item>
    <item>
      <title>实现Promise</title>
      <link>https://www.kifroom.icu/posts/shi_xian_p_r_o_m_i_s_e</link>
      <description><![CDATA[<blockquote><p>该内容由 RSS 渲染生成，最佳阅读体验请前往：<a href="https://www.kifroom.icu/posts/shi_xian_p_r_o_m_i_s_e">https://www.kifroom.icu/posts/shi_xian_p_r_o_m_i_s_e</a></p></blockquote><h2>要点：</h2>
<ol>
<li>它有3个状态，pending、fulfilled、rejected，一经改变不可逆转</li>
<li>new Promise接受一个executor()执行器，并立即执行</li>
<li>executor接受resolve和reject</li>
<li>then方法，接受2个参数，成功执行参数1，onFulfilled，参数是成功的值value；失败执行参数2， onRejected，参数是失败的值reason;</li>
<li>then链式调用，值的穿透</li>
<li>catch、finally</li>
<li>all，race，any，allsettled常用方法</li>
</ol>
<h2>基础结构</h2>
<ol>
<li>它有3个状态，pending、fulfilled、rejected，一经改变不可逆转</li>
<li>new Promise接受一个executor()执行器，并立即执行</li>
<li>executor接受resolve和reject</li>
</ol>
<pre><code class="language-js">class myPromise {
  constructor(executor) {
    this.state = 'pending'
    this.value = ''
    this.reason = ''
    const resolve = (value) =&gt; {
      if (this.state === 'pending') {
        this.state = 'fulfilled'
        this.value = value
      }
    }
    const reject = (reason) =&gt; {
      if (this.state === 'pending') {
        this.state = 'rejected'
        this.reason = reason
      }
    }
    try {
      executor(resolve, reject)
    }
    catch (error) {
      reject(error)
    }
  }
}
</code></pre>
<h2>then方法</h2>
<p>then方法，接受2个参数，成功执行参数1，onFulfilled，参数是成功的值value；失败执行参数2， onRejected，参数是失败的值reason;</p>
<pre><code class="language-js">class myPromise {
  constructor(executor) {
    this.state = 'pending'
    this.value = ''
    this.reason = ''
    const resolve = (value) =&gt; {
      if (this.state === 'pending') {
        this.state = 'fulfilled'
        this.value = value
      }
    }
    const reject = (reason) =&gt; {
      if (this.state === 'pending') {
        this.state = 'rejected'
        this.reason = reason
      }
    }
    try {
      executor(resolve, reject)
    }
    catch (error) {
      reject(error)
    }
  }

  then(onFulFilled, onRejected) {
    if (this.state === 'fulfilled') {
      onFulFilled(this.value)
    }
    if (this.state === 'rejected') {
      onRejected(this.reason)
    }
  }
}

new myPromise((resolve, reject) =&gt; {
  reject(1)
}).then((res) =&gt; {
  console.log('res', res)
}, (err) =&gt; {
  console.log('err', err)
})
</code></pre>
<p>截至目前只处理同步操作，如果在 <code>executor()</code>中传入一个异步操作的话就会失效：</p>
<pre><code class="language-js">new myPromise((resolve, reject) =&gt; {
  setTimeout(() =&gt; { reject(1) }, 2000)
}).then((res) =&gt; {
  console.log('res', res)
}, (err) =&gt; {
  console.log('err', err)
})
</code></pre>
<p><img src="https://kiftravel.oss-cn-beijing.aliyuncs.com/img/202501032157572.png" alt="无异步操作"></p>
<h2>异步任务</h2>
<p>在执行then的时候，这个promise的状态还是pending，pending时候不会执行then的2个方法参数的任何一个，所以就没得反应。换句话说，promise只有执行了resolve或reject，状态改变了，才会执行then。所以如果当调用 then 方法时，当前状态是 pending，我们需要先将成功和失败的回调分别存放起来，在<code>executor()</code>的异步任务被执行时，触发 resolve 或 reject，依次调用成功或失败的回调。</p>
<pre><code class="language-js">class myPromise {
  constructor(executor) {
    this.state = 'pending'
    this.value = ''
    this.reason = ''
    this.onFulFilledCallbacks = []
    this.onRejectedCallBacks = []
    const resolve = (value) =&gt; {
      if (this.state === 'pending') {
        this.state = 'fulfilled'
        this.value = value
        this.onFulFilledCallbacks.forEach(fn =&gt; fn())
      }
    }
    const reject = (reason) =&gt; {
      if (this.state === 'pending') {
        this.state = 'rejected'
        this.reason = reason
        this.onRejectedCallBacks.forEach(fn =&gt; fn())
      }
    }
    try {
      executor(resolve, reject)
    }
    catch (error) {
      reject(error)
    }
  }

  then(onFulFilled, onRejected) {
    if (this.state === 'fulfilled') {
      onFulFilled(this.value)
    }
    if (this.state === 'rejected') {
      onRejected(this.reason)
    }
    if (this.state === 'pending') {
      this.onFulFilledCallbacks.push(() =&gt; {
        onFulFilled(this.value)
      })
      this.onRejectedCallBacks.push(() =&gt; {
        onRejected(this.reason)
      })
    }
  }
}
</code></pre>
<p><img src="https://kiftravel.oss-cn-beijing.aliyuncs.com/img/202501032204897.png" alt="实现异步"></p>
<h2>then链式调用和值的穿透</h2>
<ol>
<li><strong>关键点1：then返回的是一个promise，</strong></li>
<li><strong>关键点2：上一次返回的值可以作为下一个then方法执行的参数</strong></li>
</ol>
<p>实现关键点1，即：</p>
<pre><code class="language-js">class myPromise {
  constructor(executor) {
    this.state = 'pending'
    this.value = ''
    this.reason = ''
    this.onFulFilledCallbacks = []
    this.onRejectedCallBacks = []
    const resolve = (value) =&gt; {
      if (this.state === 'pending') {
        this.state = 'fulfilled'
        this.value = value
        this.onFulFilledCallbacks.forEach(fn =&gt; fn())
      }
    }
    const reject = (reason) =&gt; {
      if (this.state === 'pending') {
        this.state = 'rejected'
        this.reason = reason
        this.onRejectedCallBacks.forEach(fn =&gt; fn())
      }
    }
    try {
      executor(resolve, reject)
    }
    catch (error) {
      reject(error)
    }
  }

  then(onFulFilled, onRejected) {
    let promise2 = new myPromise((resolve, reject) =&gt; {
    })
    return promise2
    // if (this.state === &quot;fulfilled&quot;) {
    // 	onFulFilled(this.value)
    // }
    // if (this.state === &quot;rejected&quot;) {
    // 	onRejected(this.reason)
    // }
    // if (this.state === &quot;pending&quot;) {
    // 	this.onFulFilledCallbacks.push(() =&gt; {
    // 		onFulFilled(this.value)
    // 	})
    // 	this.onRejectedCallBacks.push(() =&gt; {
    // 		onRejected(this.reason)
    // 	})
    // }
  }
}
</code></pre>
<p>而promise2内部需要实现之前的内容，同时由于promise 的回调是微任务（microtask），所以需要使用queueMicrotask,再将值传递下去，即：</p>
<pre><code class="language-js">class myPromise {
  constructor(executor) {
    this.state = 'pending'
    this.value = ''
    this.reason = ''
    this.onFulFilledCallbacks = []
    this.onRejectedCallBacks = []
    const resolve = (value) =&gt; {
      if (this.state === 'pending') {
        this.state = 'fulfilled'
        this.value = value
        this.onFulFilledCallbacks.forEach(fn =&gt; fn())
      }
    }
    const reject = (reason) =&gt; {
      if (this.state === 'pending') {
        this.state = 'rejected'
        this.reason = reason
        this.onRejectedCallBacks.forEach(fn =&gt; fn())
      }
    }
    try {
      executor(resolve, reject)
    }
    catch (error) {
      reject(error)
    }
  }

  then(onFulFilled, onRejected) {
    const that = this

    let promise2 = new myPromise((resolve, reject) =&gt; {
      if (that.state === 'fulfilled') {
        // onFulFilled(that.value)
        try {
          queueMicrotask(() =&gt; {
            const result = onFulFilled(that.value)
            resolve(result)
          })
        }
        catch (error) {
          reject(error)
        }
      }
      if (that.state === 'rejected') {
        // onRejected(that.reason)
        try {
          queueMicrotask(() =&gt; {
            const result = onRejected(that.reason)
            reject(result)
          })
        }
        catch (error) {
          reject(error)
        }
      }
      if (that.state === 'pending') {
        that.onFulFilledCallbacks.push(() =&gt; {
          try {
            queueMicrotask(() =&gt; {
              onFulFilled(that.value)
            })
          }
          catch (error) {
            reject(error)
          }
        })
        that.onRejectedCallBacks.push(() =&gt; {
          try {
            queueMicrotask(() =&gt; {
              onRejected(that.reason)
            })
          }
          catch (error) {
            reject(error)
          }
        })
      }
    })
    return promise2
  }
}
</code></pre>
<p>注意到</p>
<pre><code class="language-js">try {
  queueMicrotask(() =&gt; {
    onFulFilled(that.value)
  })
}
catch (error) {
  reject(error)
}
</code></pre>
<p>部分重复，优化为：</p>
<pre><code class="language-js">class myPromise {
  constructor(executor) {
    this.state = 'pending'
    this.value = ''
    this.reason = ''
    this.onFulFilledCallbacks = []
    this.onRejectedCallBacks = []
    const resolve = (value) =&gt; {
      if (this.state === 'pending') {
        this.state = 'fulfilled'
        this.value = value
        this.onFulFilledCallbacks.forEach(fn =&gt; fn())
      }
    }
    const reject = (reason) =&gt; {
      if (this.state === 'pending') {
        this.state = 'rejected'
        this.reason = reason
        this.onRejectedCallBacks.forEach(fn =&gt; fn())
      }
    }
    try {
      executor(resolve, reject)
    }
    catch (error) {
      reject(error)
    }
  }

  then(onFulFilled, onRejected) {
    const that = this
    let promise2 = new myPromise((resolve, reject) =&gt; {
      function creatFulfillMicroTask() {
        try {
          queueMicrotask(() =&gt; {
            const result = onFulFilled(that.value)
            resolve(result)
          })
        }
        catch (error) {
          reject(error)
        }
      }
      function creatRejectMicroTask() {
        try {
          queueMicrotask(() =&gt; {
            const result = onRejected(that.reason)
            reject(result)
          })
        }
        catch (error) {
          reject(error)
        }
      }
      if (that.state === 'fulfilled') {
        creatFulfillMicroTask()
      }
      if (that.state === 'rejected') {
        creatRejectMicroTask()
      }
      if (that.state === 'pending') {
        that.onFulFilledCallbacks.push(creatFulfillMicroTask)
        that.onRejectedCallBacks.push(creatRejectMicroTask)
      }
    })
    return promise2
  }
}

const p1 = new myPromise((resolve, reject) =&gt; {
  reject(1)
}).then(
  (res) =&gt; {
    console.log('res', res)
    return 'kif'
  },
  (err) =&gt; {
    console.log('err', err)
    return 'kif2'
  }
)
p1.then((res) =&gt; {
  console.log('res2', res)
}, (err) =&gt; {
  console.log('err2', err)
})

console.log('p1', p1)
</code></pre>
<p><img src="https://kiftravel.oss-cn-beijing.aliyuncs.com/img/202501041308445.png" alt="运行"></p>
<p>但是下面运行会出错：</p>
<pre><code class="language-js">new myPromise((resolve, reject) =&gt; {
  resolve(1)
}).then().then((res) =&gt; {
  console.log('res2', res)
}, (err) =&gt; {
  console.log('err2', err)
})
</code></pre>
<p><img src="https://kiftravel.oss-cn-beijing.aliyuncs.com/img/202501041334391.png" alt="运行"></p>
<p>即需要实现值穿透，then没做任何处理的时候，值会往下传，主要在then入口处做处理</p>
<pre><code class="language-js">onFulFilled = typeof onFulFilled === 'function'
  ? onFulFilled
  : v =&gt; v
onRejected = typeof onRejected === 'function'
  ? onRejected
  : (error) =&gt; {
      throw error
    }
</code></pre>
<blockquote>
<pre><code>reject的方法空时不可以写 v=&gt;v，不然永远都不会走catch，应该v=&gt;{throw v}
</code></pre>
</blockquote>
<p><img src="https://kiftravel.oss-cn-beijing.aliyuncs.com/img/202501041339420.png" alt=""></p>
<p>全部：</p>
<pre><code class="language-js">function resolvePromise(promise, result, resolve, reject) {
  resolve(result)
}
class myPromise {
  constructor(executor) {
    this.state = 'pending'
    this.value = ''
    this.reason = ''
    this.onFulFilledCallbacks = []
    this.onRejectedCallBacks = []
    const resolve = (value) =&gt; {
      if (this.state === 'pending') {
        this.state = 'fulfilled'
        this.value = value
        this.onFulFilledCallbacks.forEach(fn =&gt; fn())
      }
    }
    const reject = (reason) =&gt; {
      if (this.state === 'pending') {
        this.state = 'rejected'
        this.reason = reason
        this.onRejectedCallBacks.forEach(fn =&gt; fn())
      }
    }
    try {
      executor(resolve, reject)
    }
    catch (error) {
      reject(error)
    }
  }

  then(onFulFilled, onRejected) {
    onFulFilled = typeof onFulFilled === 'function'
      ? onFulFilled
      : v =&gt; v
    onRejected = typeof onRejected === 'function'
      ? onRejected
      : (error) =&gt; {
          throw error
        }
    const that = this
    let promise2 = new myPromise((resolve, reject) =&gt; {
      function creatFulfillMicroTask() {
        try {
          queueMicrotask(() =&gt; {
            const result = onFulFilled(that.value)
            resolve(result)
          })
        }
        catch (error) {
          reject(error)
        }
      }
      function creatRejectMicroTask() {
        try {
          queueMicrotask(() =&gt; {
            const result = onRejected(that.reason)
            reject(result)
          })
        }
        catch (error) {
          reject(error)
        }
      }
      if (that.state === 'fulfilled') {
        // onFulFilled(that.value)
        // try {
        // 	queueMicrotask(() =&gt; {
        // 		const result = onFulFilled(that.value);
        // 		resolve(result)
        // 	})
        // } catch (error) {
        // 	reject(error)
        // }
        creatFulfillMicroTask()
      }
      if (that.state === 'rejected') {
        // onRejected(that.reason)
        // try {
        // 	queueMicrotask(() =&gt; {
        // 		const result = onRejected(that.reason);
        // 		reject(result);
        // 	})
        // } catch (error) {
        // 	reject(error)
        // }
        creatRejectMicroTask()
      }
      if (that.state === 'pending') {
        that.onFulFilledCallbacks.push(creatFulfillMicroTask)
        that.onRejectedCallBacks.push(creatRejectMicroTask)
      }
    })
    return promise2
  }
}

const p1 = new myPromise((resolve, reject) =&gt; {
  resolve(1)
}).then().then((res) =&gt; {
  console.log('res2', res)
}, (err) =&gt; {
  console.log('err2', err)
})
</code></pre>]]></description>
      <author>kif</author>
      <guid>article-44</guid>
      <pubDate>Fri, 03 Jan 2025 21:48:42 +0000</pubDate>
    </item>
    <item>
      <title>javascript中如何终止请求</title>
      <link>https://www.kifroom.icu/posts/j_a_v_a_s_c_r_i_p_t_zhong_ru_he_zhong_zhi_qing_qiu</link>
      <description><![CDATA[<blockquote><p>该内容由 RSS 渲染生成，最佳阅读体验请前往：<a href="https://www.kifroom.icu/posts/j_a_v_a_s_c_r_i_p_t_zhong_ru_he_zhong_zhi_qing_qiu">https://www.kifroom.icu/posts/j_a_v_a_s_c_r_i_p_t_zhong_ru_he_zhong_zhi_qing_qiu</a></p></blockquote><p>Javascript中终止请求根据使用请求方法不同可以采用一下方式</p>
<h2>XMLHttpRequest</h2>
<pre><code class="language-js">const xhr = new XMLHttpRequest()
xhr.open('GET', '')
xhr.send()
xhr.abort()
</code></pre>
<p><code>xhr.abort()</code> 的调用时机其实是不定的，一般通过setTimeout在某个时间后终止，但由于网络关系可能在请求完成前终止也可能在请求完成后终止。</p>
<h2>Fetch</h2>
<p>等到 fetch 出来的时候，大家就在讨论关于如何正确，清楚地取消一个 fetch 请求。最早的讨论可以看这里 <a href="https://github.com/whatwg/fetch/issues/27">Aborting a fetch #27</a> ，那已经是7年前（2015年）的事情了，可以看到当时的讨论还是比较激烈的。大家感兴趣的话可以看看当时大家都主要关注的是哪些特性。</p>
<p>最终，新的规范 出来了，通过 AbortController 和 AbortSignal 我们可以方便，快捷，清楚地终止一个 fetch 请求。要注意的是，这个规范是一个 DOM 层面的规范，不是 JavaScript 语言层面的规范。现在绝大多数的浏览器环境和新版本的 Node.js 环境也都支持这个特性了。关于 AbortController 的兼容性，大家可以参考这里 <a href="https://developer.mozilla.org/en-US/docs/Web/API/AbortController#browser_compatibility">AbortController#browser_compatibility</a></p>
<pre><code class="language-js">const ac = new AbortController()
const { signal } = ac
fetch('', { signal })
  .then((res) =&gt; {
    console.log('res', res)
  })
  .catch((err) =&gt; {
    console.log('err', err)
  })
ac.abort()
</code></pre>
<h4>AbortController 的深入剖析</h4>
<p>接下来我们来讲解一下上面的代码，第一行通过 <code>AbortController</code> 创建了一个 <code>AbortController</code> 类型的实例 <code>ac</code>，这个实例上有一个 <code>abort</code> 方法和一个 <code>AbortSignal</code> 类型的 <code>signal</code> 实例。然后我们通过 <code>fetch</code> 方法去请求一个资源路径，传递给 <code>fetch</code> 的选项把 <code>ac</code> 的 <code>signal</code> 对象传递进去。<code>fetch</code> 方法如果获取到了资源就会把资源打印到控制台，如果网络发生了问题，就会捕获异常，然后把异常打印到控制台。最后，通过一个 <code>setTimeout</code> 延时，调用 <code>ac</code> 的 <code>abort</code> 方法终止 <code>fetch</code> 请求 。</p>
<p><code>fetch</code> 的 <code>options</code> 选项允许我们传递一个 <code>signal</code> 对象；<strong><code>fetch</code> 的内部会监测这个对象的状态，如果这个对象的状态从未终止的状态变为终止的状态的话，并且 <code>fetch</code> 请求还在进行中的话，<code>fetch</code> 请求就会立即失败。其对应的 <code>Promise</code> 的状态就会变为 <code>Rejected</code></strong>。</p>
<p>如何改变 <code>signal</code> 的状态呢？我们可以通过调用 <code>ac</code> 的 <code>abort</code> 方法去改变 <code>signal</code> 的状态。一旦我们调用了 <code>ac.abort()</code> 那么与之关联的 <code>signal</code> 的状态会立刻从起始状态（非终止状态）转变为终止状态。</p>
<p>我们上面只是简单地使用了 <code>signal</code> 对象，这个对象是 <code>AbortSignal</code> 类的实例，对于 <code>AbortSignal</code> 我们下面会做深入的讲解，这里暂时只需要知道 <code>signal</code> 可以作为一个信号对象传递给 <code>fetch</code> 方法，可以用来终止 <code>fetch</code> 的继续进行。</p>
<h4>批量取消多个 fetch 请求</h4>
<p>值得注意的是，我们的 <code>signal</code> 对象可以同时传递给多个请求，在需要的情况下可以同时取消多个请求；我们来看看如何进行这样的操作。代码如下所示：</p>
<pre><code class="language-javascript">const ac = new AbortController()
const { signal } = ac

const resourcePrefix = 'https://jsonplaceholder.typicode.com/todos/'
function todoRequest(id, { signal } = {}) {
  return fetch(`${resourcePrefix}${id}`, { signal })
    .then(response =&gt; response.json())
    .then(json =&gt; console.log(json))
    .catch(e =&gt; console.log(e))
}

todoRequest(1, { signal })
todoRequest(2, { signal })
todoRequest(3, { signal })

// 同时终止多个请求
ac.abort()
</code></pre>
<h4><strong>超时机制</strong></h4>
<p>如果需要实现超时中止，可以结合 <code>setTimeout</code> 和 <code>AbortController</code>。</p>
<pre><code class="language-javascript">const controller = new AbortController()
const signal = controller.signal
const timeout = 5000 // 设置超时时间，例如 5000 毫秒

fetch('https://example.com/data', { signal })
  .then(response =&gt; response.json())
  .then(data =&gt; console.log(data))

// 设置超时
setTimeout(() =&gt; {
  controller.abort()
  console.log('Request timed out')
}, timeout)
</code></pre>
<h2>使用第三方库</h2>
<p>某些第三方库，如 Axios，提供了取消请求的功能。使用这些库时，可以利用它们提供的取消令牌或类似的机制来中止请求。</p>
<pre><code class="language-javascript">const source = axios.CancelToken.source()

axios.get('https://example.com/data', {
  cancelToken: source.token
})
  .then(response =&gt; console.log(response.data))
  .catch(axios.isCancel, error =&gt; console.log('Request was canceled', error.message))

// 中止请求
source.cancel('Operation canceled by the user.')
</code></pre>
<h2>注意事项</h2>
<ul>
<li>中止请求后，<code>fetch</code> 的 Promise 会拒绝，并抛出一个 <code>AbortError</code>。</li>
<li><code>XMLHttpRequest</code> 的 <code>abort()</code> 方法会立即中止请求，并且 <code>onreadystatechange</code> 和 <code>onload</code> 事件处理程序将不会被调用。</li>
<li>中止请求并不总是立即生效，特别是在请求已经开始处理的情况下。</li>
</ul>
<blockquote>
<p>参考：</p>
<p><a href="https://segmentfault.com/a/1190000042447341">https://segmentfault.com/a/1190000042447341</a></p>
</blockquote>]]></description>
      <author>kif</author>
      <guid>article-31</guid>
      <pubDate>Thu, 02 Jan 2025 20:29:28 +0000</pubDate>
    </item>
  </channel>
</rss>