采用**异步并行生成**(Asynchronous Parallel Generation)是目前平衡“高响应速度”与“AI 生成质量”最立竿见影的方案。 其核心思路是将原来“一个请求等五个名字”的线性过程,拆分为“多个并发请求同时生成名字”。 --- ## 1. 后端重构:`MiniMaxService.java` 我们需要利用 Java 的 `CompletableFuture` 来并发调用 AI 接口。 ```java @Service public class MiniMaxService { // 模拟原有的单次生成逻辑 private NameCard callAiToGenerateSingleName(String keyword, String mode, String surname) { // 这里是原有的 MiniMax API 调用逻辑,但只要求它返回 1 个名字 // ... } public List generateNamesAsync(String keyword, String mode, String surname) { int count = 5; // 我们需要生成 5 个名字 List> futures = new ArrayList<>(); for (int i = 0; i < count; i++) { // 为每个名字开启一个异步线程 CompletableFuture future = CompletableFuture.supplyAsync(() -> { return callAiToGenerateSingleName(keyword, mode, surname); }); futures.add(future); } // 等待所有线程完成(或部分完成即可返回,提升容错) return futures.stream() .map(CompletableFuture::join) // 合并结果 .collect(Collectors.toList()); } } ``` ### 为什么这样做更快? * **线性模式**:AI 生成 5 个名字的时间 = $T1 + T2 + T3 + T4 + T5$(通常需要 8-12 秒)。 * **并行模式**:总耗时 = $max(T1, T2, T3, T4, T5)$(通常只需 2-3 秒)。 --- ## 2. 前端感知优化:伪流式展示 虽然后端并行生成了结果,但如果我们等 5 个全部完成再返回,前端仍有空窗期。我们可以配合前端做一个“分批次渲染”。 ### 修改 `index.js` 的 `fetchNames` 逻辑: 我们可以将请求拆分为两拨:一拨追求“极速响应”(先拿 2 个名字),二拨追求“完整体验”(再拿 3 个)。 ```javascript fetchNames(keyword, mode, surname) { // 1. 发起第一波请求:先取 2 个名字,让用户立刻有卡片可以翻 this.requestNamingApi(keyword, mode, surname, 2).then(firstBatch => { this.setData({ nameList: firstBatch, currentIndex: 0 }); // 2. 第一波成功后,静默发起第二波请求:补齐剩下的名字 this.requestNamingApi(keyword, mode, surname, 3).then(secondBatch => { this.setData({ nameList: [...this.data.nameList, ...secondBatch] }); }); }); } ``` --- ## 3. 仪式感补偿:Loading 文案池 为了让异步加载的 1-2 秒不尴尬,在 `home.js` 跳转到 `index.js` 时,利用一个动态的文案池来分散用户注意力。 ### 在 `index.wxml` 中添加: ```html {{loadingQuote}} ``` ### 在 `index.js` 中添加文案轮换: ```javascript const quotes = [ "正在翻阅《古今集成》...", "字里行间,寻觅归处...", "笔墨将就,意境自生...", "正在感悟山川意向..." ]; // 在 onLoad 中开启定时器 this.loadingTimer = setInterval(() => { this.setData({ loadingQuote: quotes[Math.floor(Math.random() * quotes.length)] }); }, 2000); ``` --- ## 🛠️ 实施建议 1. **后端线程池**:在使用 `CompletableFuture` 时,务必自定义一个 `Executor`(线程池),不要使用默认的 `ForkJoinPool`,防止在高并发下把后端拖垮。 2. **音律分析延迟**:如果 `ToneAnalysisService` 依然很慢,可以先返回名字和出处,音律评分字段标记为“计算中”,待卡片翻转时再动态获取。 **这套“并行生成 + 分批返回”的方案,能将用户的体感等待时间从 10 秒以上直接压缩到 2 秒左右。**