🚀 异步编程团队标准文档(Team Async Coding Standard)

42 阅读3分钟

目标:统一异步编程规范,提升可维护性与稳定性。


📘 异步编程总体原则

一、设计理念

  1. 可控性优先:异步逻辑必须可追踪、可中断、可恢复。
  2. 一致性优先:全项目统一使用 async/await 风格,禁止混用回调与 Promise 链。
  3. 异常外抛:错误必须向上传递,不得静默吞掉。
  4. 性能优先:异步并行应显式控制,避免隐式顺序阻塞。
  5. 可调试性:确保堆栈、日志、监控能清晰还原异步执行路径。

二、统一代码规范

规则说明示例
✅ 使用 async/await默认风格const data = await fetchData()
❌ 禁止 .then().then() 链式写法可读性差fetch().then().then()
✅ 错误捕获使用 try/catch 或统一包装器await safely(fn)
✅ 并行执行Promise.allallSettledawait Promise.all([a(), b()])
✅ 限制并发使用 limiter 工具await runLimited(tasks, 5)
✅ 命名规范异步函数以 Async 结尾getUserAsync()
✅ 明确类型返回 Promise<T>TypeScript 规范
❌ 禁用同步 API避免主线程阻塞readFileSync() 禁用

三、事件循环与微任务机制

graph TD
A[任务提交] --> B[宏任务队列]
B --> C[执行栈空闲]
C --> D[微任务队列]
D --> E[渲染更新或 I/O 回调]

执行顺序:
1️⃣ 执行栈清空 →
2️⃣ 执行所有微任务(Promise 回调等)→
3️⃣ 进入下一轮宏任务(如 setTimeout)。

💡 微任务在同一轮事件循环中立即执行,因此:

  • 使用 await 时,Promise 回调将优先于下一个 setTimeout 执行。
  • 大量微任务可能导致渲染延迟。

⚙️ 常见反模式与改进

反模式问题改进建议
嵌套回调 (Callback Hell)可读性差、难调试async/await 重构
Promise 链过长依赖复杂,错误难定位拆分子函数
未捕获错误Promise Rejection 无监控全局监听 + try/catch
滥用 Promise.all任一失败导致全局中断改用 allSettled
循环中 await串行阻塞性能差Promise.all 并行
空的 catch 块吞掉错误handleError() 统一处理
依赖执行时序逻辑不稳定显式 await 或任务序列化
主线程阻塞卡顿、掉帧移至 Web Worker / 后台线程

❌ 反例

getUser(id)
  .then(u => getPosts(u.id))
  .then(p => getComments(p))
  .catch(() => {}); // 错误被吞掉

✅ 推荐写法

try {
  const user = await getUserAsync(id);
  const posts = await getPostsAsync(user.id);
  const comments = await getCommentsAsync(posts);
} catch (err) {
  logger.error('Async flow failed:', err);
}

🧩 推荐模板

1️⃣ 异步函数基础模板

export async function fetchUserAsync(id: string): Promise<User> {
  try {
    const res = await api.get(`/users/${id}`);
    return res.data;
  } catch (error) {
    handleAsyncError(error, 'fetchUserAsync');
    throw error;
  }
}

2️⃣ 并行 + 限流模板

import pLimit from 'p-limit';

export async function fetchAllUsersAsync(ids: string[]): Promise<User[]> {
  const limit = pLimit(5);
  const tasks = ids.map(id => limit(() => fetchUserAsync(id)));
  return await Promise.allSettled(tasks);
}

3️⃣ 安全执行包装器

export async function safely(fn: () => Promise<any>) {
  try {
    return await fn();
  } catch (err) {
    logger.error(err);
    return null;
  }
}

4️⃣ 可取消任务模板

function cancellableFetch(url) {
  const controller = new AbortController();
  const fetchPromise = fetch(url, { signal: controller.signal });
  return { 
    promise: fetchPromise, 
    cancel: () => controller.abort()
  };
}

✅ 团队检查清单

🔍 编码检查

检查项状态说明
[ ] 所有异步函数以 Async 结尾命名规范
[ ] 所有异步调用均捕获错误无 unhandled rejection
[ ] 禁止 .then 链式调用统一风格
[ ] 所有文件 IO 为异步版本fs/promises
[ ] 所有并行操作显式控制使用 Promise.all
[ ] 无空 catch 块
[ ] 日志记录统一错误集中处理
[ ] 异步操作具备超时机制使用 Promise.race
[ ] 微任务行为与预期一致浏览器 / Node
[ ] Worker 中不访问 DOM保持线程安全

🧠 性能优化建议

  • 并发数控制:建议 5~10 并发,防止资源争夺。
  • 重试机制:使用 p-retry 提升网络稳定性。
  • 任务分组:大任务拆分为可控子任务,防止事件循环长时间阻塞。
  • 空闲任务:使用 requestIdleCallback 或 Web Worker。

📚 推荐工具

工具用途
eslint-plugin-promise检查异步反模式
p-limit并发控制
p-retry自动重试机制
p-timeout超时封装
async-local-storage异步上下文追踪

💬 团队约定语录

“异步不可怕,可怕的是没有规则的异步。”
—— 团队异步标准委员会