基于依赖关系的异步并行化:Plate 性能规范中用 better-all 消除部分依赖 Waterfall

发布时间:2026/11/10 11:12:10

基于依赖关系的异步并行化:Plate 性能规范中用 better-all 消除部分依赖 Waterfall 基于依赖关系的异步并行化Plate 性能规范中用 better-all 消除部分依赖 Waterfall【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plate本篇围绕 Plate 仓库内置的 React 性能最佳实践规则async-dependenciesDependency-Based Parallelization展开当一个页面或接口中的多个异步请求只有部分依赖关系时如何避免无谓等待把每个任务都尽早启动。读完后你将掌握三种等价的并行化写法——better-all、原生 Promise 链式组合加Promise.all()以及完全独立场景下的标准Promise.all()用法并能判断它们各自的适用边界。规则定位为什么消除 Waterfall被列为最高优先级该规则位于仓库中随 AI 技能一起分发的性能规则集 async-dependencies.md其 frontmatter 标注为impact: CRITICALimpactDescription: 2-10× improvement标签为async, parallelization, dependencies, better-all。之所以给到最高优先级从该规则集的章节定义 _sections.md 可以看到Eliminating Waterfallsasync-前缀被明确写为Waterfalls are the #1 performance killer. Each sequential await adds full network latency.也就是每一次串行await都会把一整段网络/IO 延迟累加到关键路径上。总览文件 SKILL.md 中该规则与async-parallel、async-defer-await、async-api-routes等一起构成第一优先级类别用于写代码、Code Review、重构时自动触发的判定清单。async-dependencies解决的是比完全独立的请求该并行更细的一档问题请求之间只有部分依赖时如何让没有依赖的任务不被拖住。问题场景Promise.all 挡不住部分依赖的串行段规则文档给出的典型反例是先并行取user和config但profile依赖user.id于是被排在第二个串行段const [user, config] await Promise.all([ fetchUser(), fetchConfig() ]) const profile await fetchProfile(user.id)这里的执行时间线是总耗时 ≈max(fetchUser, fetchConfig) fetchProfile。问题不在fetchConfig本身——它其实可以比profile更早结束——而在于结构上profile被写在了第一段await之后即使config与profile互不相关整体仍被迫呈现两波串行的形状。凡是拿到 A 才能查 B但 C 跟 A/B 都无关的页面数据聚合、API 路由、Server Action都会落入这个模式。方案一better-all让每个任务在最早时刻启动规则推荐的写法是引入better-allVercel 的 shuding 维护的工具库把任务声明为依赖图而不是执行顺序import { all } from better-all const { user, config, profile } await all({ async user() { return fetchUser() }, async config() { return fetchConfig() }, async profile() { return fetchProfile((await this.$.user).id) } })其工作机制从代码结构看可以这样理解all()收到一个函数对象后立即按声明启动所有顶层任务——user、config、profile三个请求在调用点同时发出而不是按书写顺序排队profile内部通过this.$.user拿到对user任务结果的 Promise 引用await它时只阻塞profile这一个任务config完全不受影响最终返回值是一个与普通对象形状一致的解构对象{ user, config, profile }调用方心智负担和普通await几乎相同。效果上总耗时从两波串行收敛为max(fetchUser fetchProfile, fetchConfig)的依赖图最长路径——即每个任务都在其前置依赖满足的最早可能时刻开始。对规则 frontmatter 声称的 2~10× 量级改善其来源正是把网络延迟叠加变为网络延迟取最大值。使用better-all的取舍它是一个额外的运行时依赖需要在package.json中声明安装本仓库apps/www/package.json当前并未引入该包此规则属于随技能分发的最佳实践落地到你的应用时需自行添加依赖。它的错误传播、超时等高级语义建议以 better-all 仓库官方文档为准。方案二零依赖等价写法Promise 链 Promise.all规则文档同时给出了不引入任何外部库的等价方案——先把所有 Promise含依赖链构造出来最后再统一Promise.all()const userPromise fetchUser() const profilePromise userPromise.then(user fetchProfile(user.id)) const [user, config, profile] await Promise.all([ userPromise, fetchConfig(), profilePromise ])这段代码与better-all版本在调度上完全等价关键只有一条纪律调用fetchUser()/fetchConfig()的语句必须出现在任何await之前。Promise 是立即开始执行的await只是暂停当前函数。只要先把三个请求都发出去后面的Promise.all就只是等待不再制造新的串行段userPromise在模块执行到该行时即发出fetchUser请求profilePromise通过.then挂到userPromise之后一旦user返回立即发出fetchProfile请求无需等待config三条链并行推进Promise.all只等待最慢的一条。这种先建链、后 await的写法也是规则集中其他条目的通用手法。例如 async-api-routes.mdPrevent Waterfall Chains in API Routes要求在 API 路由 / Server Action 中独立操作立即启动、延后 awaitexport async function GET(request: Request) { const sessionPromise auth() const configPromise fetchConfig() const session await sessionPromise const [config, data] await Promise.all([ configPromise, fetchData(session.user.id) ]) return Response.json({ data, config }) }session、config、data之间同样是部分依赖关系sessionPromise/configPromise提前构造保证了config不会白等auth。该规则结尾也明确指出对于更复杂的依赖链使用better-all自动最大化并行度见 Dependency-Based Parallelization——即本规则与async-dependencies是同一思想在不同复杂度下的两个落点。边界对照完全独立、部分依赖、嵌套三类形态为避免用错工具可以把规则集async-前缀下的几条并行化规则按依赖形状归类依赖形状代表规则推荐写法完全独立async-parallel.md直接Promise.all([fetchA(), fetchB(), fetchC()])一个 round trip 替代三个部分依赖本篇主题async-dependencies.mdbetter-all或先建链后Promise.all逐元素嵌套server-parallel-nested-fetching.md在map内对每个元素链式.then再统一Promise.allRSC 组件树顺序执行server-parallel-fetching.md用组件组合拆分await让 RSC 并行执行各子树其中逐元素嵌套一规则给出了与本篇互补的警告const chatAuthors await Promise.all( chatIds.map(id getChat(id).then(chat getUser(chat.author))) )若写成先Promise.all所有getChat再Promise.all所有getUser100 条中 1 条慢查询会阻塞另外 99 条的嵌套请求把.then链放进每个元素的 Promise 里每个元素独立推进。这与better-all的每个任务在最早时刻启动是同一原则并行化的单位应该下沉到最小依赖单元。仓库实战印证独立聚合用 Promise.allPlate 自身的 Next.js 站点apps/www中可以看到与规则一致的实践。以聚合 LLM 可读 Markdown 的 llm.ts 为例export const getPlateLLMFullMarkdown async (pages: PlateLLMPage[]) { const content await Promise.all( pages.map((page) getPlateLLMPageMarkdownFromPage({ page })) ) return content.join(\n\n) }这里各 page 的 Markdown 化完全相互独立因此直接pages.map(...)并发 一次Promise.all收集属于async-parallel的标准形态若未来某个 page 的转换需要依赖另一个 page 的元数据就可以按本篇的先建链或better-all模式升级为部分依赖并行。落地建议与注意事项先画依赖图再选模式三个请求两两独立 → 普通Promise.all存在用到 A 的结果才能发起 BC 无关的部分依赖 → 本篇两种写法逐条记录的二级请求 → 元素级.then链。零依赖写法优先任务图变复杂再上 better-all手写先建链后 await没有额外依赖但任务一多≥4 个且依赖关系交错手写链容易漏发某个请求或写反依赖方向better-all的声明式任务图更不易出错。不要为看起来更整齐引入串行本规则反例的Promise.all([...]) 后续单独await在语法上完全合法危害只在于多出的串行段重构时应以每个请求最早启动时刻为准绳检查时间线。配套检查并行化之外规则集还建议用 async-defer-await.md把await推迟到真正使用的分支与 async-cheap-condition-before-await.md廉价同步条件先于异步标志判断消除根本不必要的异步调用——先删掉不必要的等待再对剩下的必要等待做并行化收益叠加。适用前提以上模式适用于 Node.js/浏览器中请求发出即开始执行的 Promise 型 IO若底层 API 是惰性执行调用仅返回计划、稍后才真正发起先建链写法不会达到并行效果需要确认底层实现为立即执行语义。小结async-dependencies规则的核心结论可以压缩为一句话串行段不是由await的位置决定的而是由依赖被声明的时机决定的。无论是better-all的声明式任务图还是先创建全部 Promise、最后统一Promise.all()的原生写法目标都一样——把每个请求的启动时刻推进到其前置依赖满足的最早点让总耗时收敛到依赖图最长路径而非所有路径之和。这一模式在页面数据聚合、API 路由、RSC 嵌套查询中都可直接套用也是 Plate 随仓库分发的 React 性能技能中CRITICAL 级优化清单的第一优先级条目。【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plate创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/11/10 11:35:40

vibe coding焦虑自救:9个开源工具打造AI编程安全护栏

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

2026/11/10 11:33:59

Flask路由详解:从动态路由、转换器到优先级排序与调试技巧

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

2026/11/10 14:19:36

在海南能考电工证吗吗 电工证含金量到底有多高

在海南能考电工证吗吗 电工证含金量到底有多高 你是不是也在纠结“在海南能考电工证吗吗”,怕被中介骗钱,不知道去哪报名?别急,我来帮你一把。电工证这个证, 含金量 确实高,但关键得搞清楚怎么考、怎么用,别一不小心花了冤枉钱还拿不到证。…

2026/11/10 14:19:36

物业中级电工证是哪种?2026河南最新政策怎么应对?

物业中级电工证是哪种?2026河南最新政策怎么应对? 工地太忙根本没时间复习考试,尤其是像洛阳涧西区这些施工任务重的区域,电工证的考试和复审都成了很多一线操作人员的心头难。2026年河南最新政策对特种作业证的报考流程、考试内容、证书管理都有…

2026/11/10 14:19:35

新会电工证培训学校全流程办理指南郑州报考避坑指南

新会电工证培训学校全流程办理指南郑州报考避坑指南 你是不是也在担心,自己学历不高,连个电工证都报不上?别急,今天咱们就来聊一聊【新会电工证培训学校】怎么报名、怎么考,还有你最关心的 学历门槛 和 郑州报考避坑指南…

2026/11/10 14:14:35

招聘有电工证的电工实操考试心里没底?保姆级教程教你一次过

招聘有电工证的电工实操考试心里没底?保姆级教程教你一次过 实操考试心里没底怕挂科?你不是一个人。很多电工在准备【招聘有电工证的电工】岗位时,最担心的不是理论知识,而是考试现场的操作流程。特别是低压电工证和高压电工证,实操部分稍有失误,就可能…

2026/11/10 8:12:38

电工证丢失还能补吗?千万别踩坑,丢了证等于失业

电工证丢失还能补吗?千万别踩坑,丢了证等于失业 你正在找工作,但手里的电工证突然丢了,这下怎么办?别急,先别慌, 电工证丢失还能补吗 ?答案是肯定的,但 千万别踩坑 ,补办流程如果不了解,可能会耽误你上岗、甚至影响到你的收入。…

2026/11/10 0:01:28

学历不高怕报不上名?考电工证报名费+网上查询全攻略来了

学历不高怕报不上名?考电工证报名费+网上查询全攻略来了 你是不是也担心自己学历不高,考电工证报名费太贵,根本报不上名?别急,今天就来给你讲讲,怎么用最少的钱,把证拿到手,还能在工地上多挣点钱。 电工证报名费多少钱?网上查询是关键…

2026/11/10 0:01:29

绍兴考电工证培训机构怎么选?2026河南最新政策别错过

绍兴考电工证培训机构怎么选?2026河南最新政策别错过 怕考不过白交培训费?你不是一个人。2026河南最新政策出台,对电工证考试、报名、培训、复审都有明确规定。选择绍兴考电工证培训机构,别再踩坑,下面一步步教你避坑。…

2026/11/9 6:30:27

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/10 10:29:37

SSM电子书店源码全解析:结构、原理、部署与排错实战

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

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑