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() 替代手动 Promisetools
UI/UX 与布局设计——做界面布局/结构/导航/组件/交互的设计决策。触发:做UI/UX/布局/排版/导航/组件/交互/栅格/响应式/图表选型/字体配对。按媒介路由 HTML/Web、原生 App(iOS/Android/桌面)、CLI、TUI。需后端动态系统不适用;配色/主题/色板走姊妹 skill design-color。
tools
主题与配色设计——做颜色搭配/调色板/主题/品牌色阶/暗模式的设计决策。触发:选配色/调色/主题/色板/品牌色/暗模式/对比度/色盲/UI风格。按媒介路由 HTML/Web(CSS变量)、原生App(平台token)、CLI(ANSI)、TUI(真彩/256/16降级)。保证可访问性(对比度/色盲安全)。需后端动态系统不适用;UI/UX 布局/组件/交互走姊妹 skill design-uiux。
tools
跨任意组件(plugin/skill/agent/command)的验证驱动优化循环纪律 skill。当用户要优化某个已有组件却无明确方向、或要防止改了反而更差(自评乐观偏差 / 多维同改归因失效 / 为凑分加废话膨胀)、或要把一套通用「评分→单变量改→改后验证严格更好才留否则回滚→触顶停」的纪律套到任意组件上时使用。管优化过程本身的纪律(validation gate / ratchet / 独立验证 / 触顶停),不评单组件深度(交 skill-dev),不查插件接线(交 plugin-dev)。仅手动 /optimize-any 触发。
data-ai
两层规则记忆 (基于 .skein/spec)。planning 时 recall 召回相关规则、task finish 后 sediment 沉淀学习 + prune 自动精简过期/重复/断链规则。core 常驻硬规 + recall 按需召回, 经判定门自动写盘 (不逐次问用户)。产出 .skein/spec 下 core/recall 规则文件 + index。另支持空仓 bootstrap 播种规则基线、记忆大面积失效 (大重构/换栈) 时 reconstruct 可逆归档后按项目类型分型重建、maintain 手动体检 (超预算/stale/断链/重复/废弃, --apply 自动修复)、auto-fix (Stop hook 写 .pending-fix 标记 → main 派 skein-specer bg 跑 maintain --apply 全自动修, 断链只报告)。