我用 stock-sdk 做了一个纯前端的 A 股看板
先交代一下背景:我平时看盘有个“坏习惯”——开一堆 APP/网页,然后在它们之间疯狂切换,最后得到的不是信息,而是焦虑。 所以干脆自己写一个:打开一个页面,把常用的行情、板块、分时、K 线、资金面、筛选工具都塞进去。 这个项目就是 stock-dashboard:React + TypeScript + Vite 的前端看板。数据源全部来自 stock-sdk,没有后端、没有 Python 定时脚本,就是纯前端直接拉数据。 体验地址我直接放这: stock-dashboard (如果你也想摸鱼,记得开小窗)。 先说最关键的:数据层怎么接的?项目里我把 stock-sdk 的调用统一收口到了 src/services/sdk.ts。 这里做了三件很“工程化但不装”的事: SDK 单例 + 重试new StockSDK({ timeout, retry }),网络抖一下、接口偶发超时这种事就交给 SDK 自己兜底(最多重试 3 次,指数退避那套)。 内存缓存(TTL)行业/概念列表这种 10 秒内不会突然“宇宙大爆炸”的数据,缓存一...
我写了个“能少写点代码”的汇率 SDK:Exchange Rate SDK
如果你做过电商、出海、旅行、订阅制产品,或者任何“用户可能会拿着不同货币来烦你”的业务,你大概率经历过这种对话: 产品/老板:这个页面加个汇率换算吧,很简单的。你:行啊。(内心:又来了) 因为“很简单”的背后通常是: 选个汇率接口(最好不要 key,不要注册,不要配额,不要收费……懂的都懂) 处理超时、网络抖动、429/5xx(不然线上会让你看到人间真实) 缓存(不然你会被同事/自己/用户一起打爆) 货币列表(最好还能搜中文,不然“人民币”三个字能让你写一整套映射) 最后再把这些东西重复粘贴到下一个项目里,继续假装这叫“沉淀” 于是我写了 exchange-rate-sdk:一个轻量级、跨平台(浏览器 + Node.js)的汇率查询 SDK。它的目标就一个:把这些“每个项目都要做一遍、又不想做一遍”的活儿,打包成一个你能直接用的工具。 如果你只想先试试水,直接去 Playground:https://chengzuopeng.github.io/exchange-rate-sdk/ 顺手把链接也放这儿(方便你收藏/转发...
从单文件到可扩展:我给 stock-sdk 做的一次架构升级
这篇文章不是一份“正式的技术方案文档”,而是站在工具作者的视角,记录我在给 stock-sdk 做一次比较大的架构升级时,真实的思考过程、取舍以及落地方案。 如果你也维护过一个“越写越大的 SDK / 工具库”,大概率会在下面的某些场景里看到自己的影子。 背景:当一个 SDK 开始“失控”在很长一段时间里,stock-sdk 的代码结构其实非常简单: 一个 sdk.ts 一些工具函数 一份类型定义 这样写在早期非常爽: 新功能直接往里加 一个文件就能看到所有逻辑 调试也很直观 但问题在于,它会一直长。 当 sdk.ts 的体量来到一千多行之后,一些信号开始变得明显: 找一个方法要不停地滚动 改一个功能,总担心影响到旁边完全不相关的逻辑 测试文件也跟着一起膨胀 心理上开始抗拒“再往这里加东西” 这不是某一行代码的问题,而是结构已经不再适合继续演进。 我给这次重构定下的几个底线在真正动手之前,我先给自己划了几条“红线”,否则很容易越改越乱: 对外 API 必须完全兼容(这是 SDK,不是业务项目) 可以慢慢迁,但不能一次性推翻重来 结构要能撑得住未来继...
stock-sdk:为前端设计的股票行情 SDK
做过金融相关的前端(哪怕只是行情看板 Demo),大概率都会遇到一些工程层面的麻烦: 股票行情工具大多集中在 Python 生态,前端难以直接使用 为了拉数据,不得不自建一层后端中转 接口格式混乱、字段不友好,还要处理 GBK 编码 全市场批量拉取时,并发、限频、容错一堆细节要自己兜 stock-sdk 做的事很朴素:把这些公开数据源的“工程脏活”封装起来,提供一个 零依赖、TypeScript 友好、浏览器与 Node.js 都能用 的行情 SDK,让前端可以像调用普通 API 一样获取行情、K 线和分时数据。 前阵子有个朋友问我:抓股票行情数据是不是必须学 Python? 我说不一定啊,JavaScript 也能搞。 他不信,说你随便找个能用的 JS 股票数据库试试? 我还真试了。然后发现……他说得对,真没几个能用的。 被迫营业事情是这样的。 我本来只是想给自己做个小工具,每天早上打开浏览器就能看到自选股涨跌的那种。功能很简单,就是个看板页面,技术上也没什么难度。 难的是数据从哪来。 找了一圈才发现,股票数据这块,Python 生态是真的强。AkShare、Tusha...
React 源码深潜(五):Memoization 双子星与 Suspense 的悬停魔法
在前四篇中,我们走完了 React 核心架构的”主线任务”:Fiber、渲染流程、Hooks、并发模式。从这一篇开始,我们进入”支线副本”——那些你日常开发中高频使用,但底层原理很少有人说清楚的 API。 本篇覆盖两个主题:Memoization 双子星(useMemo / useCallback) 和 Suspense 机制。它们一个关于”跳过不必要的计算”,一个关于”等待异步数据”,但底层都深深扎根在 Fiber 链表和工作循环中。 第一部分:性能优化的双子星——useMemo 与 useCallbackuseMemo 和 useCallback 在社区里经常被过度使用,也经常被误解。要搞清楚什么时候该用、什么时候不该用,最好的方式就是看看它们在源码里到底做了什么——你会发现,它们的实现朴素得令人意外。 1. 底层存储结构在第三篇中我们讲过,所有 Hooks 的数据都挂在 Fiber 节点的 memoizedState 链表上。useMemo 和 useCallback 也不例外,它们存的只是一个简单的二元组: 12345// 每个 useMemo / use...
React 源码深潜(四):并发模式与 useTransition 的"时间魔法"
在前三篇中,我们构建了 Fiber 架构(骨架)、梳理了渲染流程(经络)、解析了 Hooks 原理(记忆)。现在,我们要解决最后一个、也是最直接影响用户体验的问题: 如何让应用在繁重的计算下依然保持丝滑的响应? 这就是 React 18 并发模式要回答的核心命题。 1. 经典难题:输入框卡顿之谜想象一个常见的场景:搜索框。 用户在输入框打字,下方需要根据输入内容渲染一个包含几千条数据的列表。 这里有两个性质完全不同的任务: 输入回显(High Priority):用户敲键盘,屏幕需要立即显示字符,延迟超过 100ms 就会产生明显的”卡顿感” 列表渲染(Low Priority):下方的搜索结果需要大量 DOM 操作,可能要跑几百毫秒 在 React 18 之前(或不加优化): React 会把这两个更新当成一回事,放在同一个渲染任务里处理。一旦开始渲染列表,主线程就被占满。用户敲键盘,但屏幕上字出不来——因为浏览器正忙着画那几千条列表。 123456789101112131415用户体验时间线(React 17 / 无优化): 用户按下 'a' ...
React 源码深潜(三):Hooks 的幻术——闭包快照与链表存储
在 React 16.8 之前,只有 Class 组件才能保存状态。Hooks 的出现让函数组件拥有了”记忆”,但如果你停下来想一想,会发现一个反直觉的事实:函数执行完毕后,所有局部变量都会被销毁——React 到底把状态藏在了哪里? 本篇从这个问题出发,完整拆解 Hooks 的两大核心原理。 1. 直击灵魂的拷问:状态去哪了?先看这段最简单的代码: 1234567function Counter() { const [count, setCount] = useState(0); console.log('Render:', count); return <button onClick={() => setCount(count + 1)}>{count}</button>;} 当我们点击按钮: setCount(1) 触发 React 更新 Counter 函数重新执行 再次运行到 const [count, setCount] = useState(...
React 源码深潜(二):双缓存与渲染流程的"两步走"策略
在第一篇中,我们理解了 Fiber 是为了解决”卡顿”而生的。那么,React 拿到 Fiber 链表后,到底是如何一步步把它变成网页上的真实像素的呢? 本篇我们进入 React 更新流程的核心地带:Render 阶段(打草稿)和 Commit 阶段(去发布),以及连接它们的双缓存机制。 1. 核心模型:Render 与 Commit 的职责划分React 将每一次 UI 更新严格分成了两个阶段,这不是设计上的”洁癖”,而是为了实现可中断更新的前提条件。 特性 Render 阶段(协调) Commit 阶段(提交) 工作内容 在内存中计算 Fiber 树的差异,标记增删改 将计算结果一次性应用到真实 DOM 是否可中断 是(配合 Scheduler 时间切片) 否(必须同步执行完) 对用户可见 不可见(全在内存中进行) 可见(用户看到界面变化) 内部核心函数 beginWork / completeWork commitMutationEffects / commitLayoutEffects 有无副作用 无(纯计算) 有(D...
React 源码深潜(一):走进 Fiber 架构的"操作系统"
理解 React 的宏观架构,就像是在观察一个高效运行的微型操作系统。它不仅仅是把 UI 渲染出来,更是在毫秒级的时间里管理着资源的分配和任务的优先级。 本文是 React 源码系列的第一篇,我们从浏览器的帧预算讲起,搞清楚 React 为什么要做 Fiber 这件事,以及 Fiber 到底是什么。 1. 核心挑战:浏览器的”16.6ms”军令状显示器的刷新率通常是 60Hz,这意味着浏览器每秒需要刷新 60 次画面。留给每一帧的时间只有: 11000ms / 60 ≈ 16.6ms 在这一帧内,浏览器需要完成以下工作: 处理用户输入(点击、滚动、按键) 执行 JavaScript 计算样式和布局(Style & Layout) 绘制画面(Paint & Composite) 这里的要害在于:JavaScript 执行和 UI 渲染共享同一个主线程。如果 React 的 Diff 算法跑了 100ms,浏览器在这期间无法响应用户输入,也无法绘制下一帧——用户看到的就是画面”卡死”了。 为了直观理解,可以想象一条流水线: 1234567891011121...
WebGL 基础入门篇
本篇侧重 WebGL 基础,默认你是“没写过/刚入门”的状态。 文章里会穿插一些小 demo(我更喜欢边跑边理解,而不是只看概念)。 会涉及少量矩阵/坐标的推导,不想深究也没关系,先把流程和 API 跑通就已经很够用了。 简介WebGL 是什么WebGL,全称 Web Graphics Library,是一种用于在网页浏览器中渲染 2D 和 3D 图形的 API。它基于 OpenGL ES 2.0,通过 JavaScript 在不使用插件的情况下,直接利用 GPU 进行硬件加速渲染。 WebGL 是现代浏览器(如 Chrome、Firefox、Safari)支持的标准,能够在 PC、手机等多平台上运行。 WebGL 的应用场景游戏开发:许多浏览器游戏通过 WebGL 实现复杂的 3D 场景和交互效果。 图形/游戏引擎 数据可视化:使用 WebGL 可以在网页上实现高性能的 3D 数据可视化工具。 交互式 3D 网页:可以实现像 3D 地图、虚拟展览等内容。百度地图 VR/AR:结合 WebGL 和 WebXR API,可以在网页上开...
