跳到主要内容

21 篇博文 含有标签「前端」

查看所有标签

LangChain 还是 pi-agent?两套 Agent 框架的哲学差异(含同任务实测对照)

· 阅读需 8 分钟

「我该用 LangChain 还是自己写 / 换别的?」——这是开始做 Agent 时最常见的纠结。这篇把 LangChain(JS)pi-agent 摆在一起比:不是比谁的 API 漂亮,而是比它们对「Agent 应该由谁来管」这件事的答案

为了不空谈,我给同一类任务(一个会调工具的查天气 Agent)在两边各写了一份代码并真跑起来:pi 侧用内置的 fauxProvider(不需要 key),LangChain 侧用真实模型端点(DeepSeek 的 Anthropic 兼容接口)。文中的事件序列、消息序列、最终回答都是真实输出

版本:@earendil-works/pi-ai / pi-agent-core 0.85.1langchain 1.5.11 / @langchain/langgraph 1.4.15(2026-09 npm 实测)。本站已有两个系列:pi-agent 系列LangChain + LangGraph 系列

LangGraph 的 reducer 有几种模式?顺带把 Annotation 讲透

· 阅读需 8 分钟

LangGraph 入门 那篇里,我把 reducer 一笔带过:「(a,b)=>b 是覆盖,a.concat(b) 是追加」。但那只是两种写法,不是全部模式——真正的问题是:

同一个 key 被写入多次时,状态该怎么合?

这就是 reducer 要回答的唯一问题。这篇把它讲全:Annotation 的完整用法、reducer 的几种模式、它什么时候被调用、调用几次、以及我把每种行为都真实跑出来的结果(含两个报错,都是实测)。

声明:以下行为全部在 @langchain/langgraph 1.4.15(Node 24)跑出来的,输出是真实的。不同版本行为可能微调,以你的实际运行为准。

不用框架,自己管好前端请求:缓存、竞态与取消的一般解法

· 阅读需 11 分钟

上一篇《TanStack Query 实战》里,一个收藏星标靠 useQuery / useMutation 把「缓存、竞态、取消、同步」全接管了,一行都没手写。但那篇留下一个反向的问题:如果不引入框架,这些事自己怎么写?

「库帮你做了」和「你知道它做了什么」是两回事。这篇把前端请求里最头疼的几件事——状态管理、缓存、去重、竞态、取消、重试——用纯手写的方式逐层拆开,讲清每一种的一般解法。理解了这些,再回头看 TanStack Query / ahooks,你就能看懂它们「为什么这么设计」。

前端 RUM 自建方案调研:从采集到报表的每一步

· 阅读需 13 分钟

上一篇《前端 RUM:真实用户性能监测》讲清了 RUM 是什么、怎么用浏览器的 Performance API 采数据。但「采集」只是开始——真正的工程难题在后面:数据怎么不丢地送出去、怎么存得又快又省、怎么从海量原始数据里榨出结论、怎么把结论变成报表和告警

这篇把「自建 RUM」当成一条完整流水线来拆,深入每一个环节:采集 → 传输 → 接入 → 存储 → 聚合 → 分析 → 报表。每一层都给出取舍和可落地的方案。

useEffect 三种用法,在 commit 阶段的挂载时机(源码级辨析)

· 阅读需 7 分钟

useEffect 是渲染后异步执行的副作用」——这句话对,但不完整。同样是 useEffectuseEffect(fn)useEffect(fn, [])useEffect(fn, [a])commit 阶段触发的时机和条件完全不同;再叠上 useLayoutEffect,时机又变了。

本文从 React 源码(open/react)出发,把「不同使用方式 → 不同 flag → commit 阶段不同挂载时机」这条链讲清楚。

用 D2 画流程图:另一种「文本即图表」的打开方式

· 阅读需 3 分钟

Mermaid 大家都很熟了,但「文本即图表」还有另一个后起之秀——D2(d2lang.com),一个用 Go 写的声明式图表语言。它把布局交给引擎(dagre / ELK)自动排版,写图就像写数据一样:节点、连线、容器,全部是声明。

这篇博客本身就在用 D2 画图——下面的流程图和应用架构图都是 ```d2 代码块在构建时编译成的 SVG。你可以直接看效果,再决定要不要入坑。

TanStack Query 实战:一个「收藏星标」的乐观更新

· 阅读需 13 分钟

收藏功能几乎是每个内容产品的标配,但它恰恰是「手写 fetch 最容易写脏」的一类交互:点一下,UI 要立刻翻转,网络请求在后台跑,失败还得翻回去。这背后其实藏着一串问题——loading 怎么禁按钮?等网络还是先反馈?失败怎么恢复?详情页、列表页、收藏页三处的数据怎么同步?

这篇文章用项目里一个真实的 FavoriteStar 组件,讲清楚 TanStack Query 是怎么把这四件事全部接管的。你会发现:这些逻辑一行都没手写,全靠 useMutation 的生命周期钩子。

React 19 弃用 forwardRef:ref 传参方式的前后对比

· 阅读需 5 分钟

在 React 里,「把一个 DOM 节点的引用从父组件传给子组件」——这么简单一件事,React 18 及之前却得包一层 forwardRef

import { forwardRef, useRef } from 'react';

const FancyInput = forwardRef(function FancyInput(props, ref) {
return <input ref={ref} {...props} />;
});

function App() {
const inputRef = useRef<HTMLInputElement>(null);
return <FancyInput ref={inputRef} />;
}

为什么不能直接写 function FancyInput(props) 然后取 props.ref?因为在 React 19 之前,ref 不是普通 prop——它是 React 内部的特殊属性:类组件通过它拿到实例引用,而函数组件默认什么都收不到,只能靠 forwardRef 显式接收再转发。

React 19 把这件事彻底改掉了:ref 变成了普通 prop,forwardRef 被官方标记为 deprecated(弃用,但兼容可用)。新代码不再需要它。

为什么 React 调度器用小顶堆做任务队列:数据结构、排序与时间复杂度的取舍

· 阅读需 14 分钟

React 的 Scheduler 本质是一个「任务队列 + 时间切片器」:任意时刻都可能有人提交任务,调度器要不断回答同一个问题——下一个执行谁? 它的答案是按「过期时间」排序,谁先过期谁最紧急,先执行谁。

实现这个队列用的数据结构,不是数组加排序,也不是链表,而是一个几十行的小顶堆(Min-Heap)。这篇文章从队列的需求出发,对比各种方案的时间复杂度,讲清楚为什么堆是最优解。

前端 RUM:真实用户性能监测

· 阅读需 7 分钟

「网站加载快吗?」这个问题,实验室(Lighthouse、压测)回答不了真实答案——用户可能在弱网、地铁、安卓千元机在后台还挂着几十个 App。性能是分用户、分设备、分网络、分地区的,只有从真实用户浏览器里采集到的数据,才反映真实体验。

这就是 RUM(Real User Monitoring,真实用户监控)——从真实用户的页面里采集性能与错误数据,用「真实发生」代替「假设场景」。