plugins/languages/javascript/skills/async/SKILL.md
JavaScript异步编程规范:async/await、Promise链式调用、Promise.withResolvers、AbortController取消控制、Streams API流处理。处理并发请求、异步流程控制、超时取消、数据流时加载。
npx skillsauth add lazygophers/ccplugin plugins/languages/javascript/skills/asyncInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
| Agent | 说明 | | ----- | ---- | | dev | JavaScript 开发专家 | | debug | JavaScript 调试专家 | | test | JavaScript 测试专家 | | perf | JavaScript 性能优化专家 |
| 场景 | Skill | 说明 | |------|-------|------| | 核心规范 | Skills(javascript:core) | ES2025-2026 标准、ESM、工具链 | | 安全编码 | Skills(javascript:security) | CORS、CSP、输入验证 |
// 所有 await 必须有错误处理
async function fetchData(url) {
try {
const response = await fetch(url);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return await response.json();
} catch (error) {
console.error('Fetch failed:', error);
throw error;
}
}
// try-catch 中必须 return await(否则错误不被捕获)
async function safeFetch(url) {
try {
return await fetch(url); // 必须 await
} catch (e) {
// 这样才能捕获错误
throw new Error(`Request failed: ${e.message}`);
}
}
// Promise.allSettled - 等待全部完成(推荐,处理部分失败)
const results = await Promise.allSettled([
fetchUser(id),
fetchPosts(id),
fetchComments(id),
]);
const succeeded = results.filter(r => r.status === 'fulfilled').map(r => r.value);
const failed = results.filter(r => r.status === 'rejected').map(r => r.reason);
// Promise.all - 全部成功或快速失败
const [user, posts] = await Promise.all([
fetchUser(id),
fetchPosts(id),
]);
// Promise.withResolvers (ES2024) - 外部控制 resolve/reject
const { promise, resolve, reject } = Promise.withResolvers();
element.addEventListener('click', () => resolve('clicked'));
const result = await promise;
// Promise.any - 第一个成功
const fastest = await Promise.any([
fetch('https://cdn1.example.com/data'),
fetch('https://cdn2.example.com/data'),
]);
// 超时控制
async function fetchWithTimeout(url, timeout = 5000) {
const controller = new AbortController();
const id = setTimeout(() => controller.abort(), timeout);
try {
const response = await fetch(url, { signal: controller.signal });
return response;
} catch (error) {
if (error.name === 'AbortError') {
throw new Error(`Request timeout after ${timeout}ms`);
}
throw error;
} finally {
clearTimeout(id);
}
}
// 竞态条件处理 - 取消过期请求
let activeController = null;
async function loadData(id) {
activeController?.abort();
activeController = new AbortController();
const response = await fetch(`/api/data/${id}`, {
signal: activeController.signal,
});
return response.json();
}
// AbortController 统一清理事件监听
function setupListeners(element) {
const controller = new AbortController();
const { signal } = controller;
element.addEventListener('click', handleClick, { signal });
element.addEventListener('keydown', handleKey, { signal });
window.addEventListener('resize', handleResize, { signal });
return () => controller.abort(); // 一次性清理所有监听
}
// 读取大文件流
async function processStream(url) {
const response = await fetch(url);
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value, { stream: true });
processChunk(chunk);
}
}
// Array.fromAsync (ES2025)
async function* generateItems() {
for (let i = 0; i < 10; i++) {
yield await fetchItem(i);
}
}
const items = await Array.fromAsync(generateItems());
// worker.js
self.onmessage = (event) => {
const result = heavyComputation(event.data);
self.postMessage(result);
};
// main.js - ESM Worker
const worker = new Worker(
new URL('./worker.js', import.meta.url),
{ type: 'module' }
);
worker.postMessage(data);
worker.onmessage = (e) => handleResult(e.data);
worker.onerror = (e) => handleError(e);
| 现象 | 问题 | 严重程度 |
|------|------|---------|
| await 无 try-catch | 未处理的 Promise rejection | 高 |
| return fetch() 在 try 中 | 应 return await fetch() 否则错误不被捕获 | 高 |
| Promise.all 不容错 | 应使用 Promise.allSettled 处理部分失败 | 中 |
| 手动创建 Promise | 应使用 Promise.withResolvers() | 低 |
| 无超时控制 | 应使用 AbortController 设置超时 | 中 |
| 竞态条件 | 应使用 AbortController 取消过期请求 | 高 |
| 回调嵌套 | 应使用 async/await | 高 |
return awaitPromise.allSettled() 处理并行Promise.withResolvers() 替代手动 Promisedevelopment
Go 数据库规范——GORM Model 命名 ModelXxx、表名单数、枚举 uint8 + 常量、索引 idx_ 前缀 + deleted_at leading column、禁 time.Time 统一 int64 unix、禁指针/nullable 字段、TEXT/BLOB/JSON 禁 default、AutoMigrate 禁改主键。设计 DB model、写 GORM tag、建索引、做 migration 审查时触发。
development
Go HTTP API 规范——响应始终 200 + body code 字段、路由 /api/* 全 POST 单段 <Action><Model>、中间件逐路由注册禁 Group(prefix,mw...)、handler 仅返回 (rsp,error)、认证走 header。设计 HTTP API、写路由/handler/中间件时触发。
development
Go 项目结构规范——三层架构(API → Impl → State)、全局状态模式、internal/ 私有包、cmd/ 仅 main.go、go.work 多模块、禁止 Repository 接口和 DI 容器、struct 公共字段开头全 omitempty、handler var rsp 顶声明、禁 legacy migration。设计项目骨架、新建目录、组织包、做架构评审时触发。
development
Go 命名规范——Id/Uid 字段(非 ID)、IsActive/HasMFA 布尔前缀、CreatedAt 时间字段、接收者统一用 p、包名全小写无下划线、泛型类型参数描述性命名、集合字段 xxx_list 禁 xxxs 复数、Enum 0 值 XxxNil 禁 Unknown、禁 Status 统一 State、Set/Update 语义区分。定义结构体字段、函数、变量、包、接收者名、泛型、枚举时触发。