
本文详解如何利用 p-limit 的 `pendingcount` 属性实现任务进度可视化,通过定时轮询动态计算并输出“还剩 n 个 api 请求未完成”,适用于 cli 工具或后台任务监控场景。
p-limit 是一个轻量但强大的并发控制工具,它通过 limit(fn) 包装异步函数,确保任意时刻最多只有指定数量(如 pLimit(3))的任务在执行中。其暴露的 .pendingCount 属性是理解当前执行状态的关键:它表示当前已提交但尚未开始执行(即处于等待队列中)的任务数量——注意,它不包含正在运行中的任务(.running),也不包含已完成任务。
要实现类似 “我们还剩 n 个 API 调用未发起” 的实时提示,核心逻辑是:
- 总任务数固定(如 urls.length);
- 已发起的任务数 = 总数 − pendingCount(因为所有未 pending 的任务,要么正在运行,要么已结束);
- 因此,剩余待发起请求数 = pendingCount;
- 进度百分比可近似为 (已完成数 / 总数) × 100 ≈ ((总数 − pendingCount) / 总数) × 100。
以下是一个生产就绪的示例,支持终端实时刷新进度条(兼容 Node.js 环境):
import pLimit from 'p-limit'; const urls = [ 'https://www.google.com/search?q=1', 'https://www.google.com/search?q=2', 'https://www.google.com/search?q=3', 'https://www.google.com/search?q=4', 'https://www.google.com/search?q=5', 'https://www.google.com/search?q=6', 'https://www.google.com/search?q=7', 'https://www.google.com/search?q=8', ]; const limit = pLimit(3); const promises: Promise[] = []; for (const url of urls) { // 注意:此处不立即执行 fetch,而是交由 limit 调度 promises.push(limit(() => fetch(url))); } // 启动进度监控(每秒更新一次) const progressInterval = setInterval(() => { const remaining = limit.pendingCount; // ✅ 关键:当前排队等待执行的任务数 const completed = urls.length - remaining - limit.running; const progress = Math.round(((completed / urls.length) * 100)); // 终端覆盖式输出(保持单行刷新) process.stdout.clearLine(0); process.stdout.cursorTo(0); process.stdout.write(`✅ 进度: ${progress}% | 运行中: ${limit.running} | 排队中: ${remaining} | 总计: ${urls.length}`); }, 1000); try { const results = await Promise.allSettled(promises); // 清理定时器 clearInterval(progressInterval); // 处理结果 results.forEach((result, index) => { if (result.status === 'fulfilled') { console.log(`✓ ${urls[index]} → ${result.value.status}`); } else { console.error(`✗ ${urls[index]} → ${result.reason}`); } }); console.log('\n? 所有请求已完成!'); } catch (error) { clearInterval(progressInterval); throw error; }
⚠️ 重要注意事项:
- pendingCount 仅反映排队中、尚未被调度执行的任务数,不包括 running 中的任务。因此,“剩余请求数”严格等于 pendingCount,而非 pendingCount + running(后者是未完成总数)。
- 定时器必须在 Promise.allSettled() 完成后显式清除(clearInterval),否则会持续运行造成内存泄漏。
- process.stdout.clearLine() 和 cursorTo() 仅在 Node.js 的 TTY 环境(如终端)中有效;若需浏览器环境支持,应改用 DOM 更新(如 document.getElementById('progress').textContent = ...)。
- 若任务创建与调度存在延迟(例如异步生成 URL),请确保 pendingCount 统计前所有任务均已注册到 limit(),否则初始值可能不准确。
总结:pendingCount 是 p-limit 提供的轻量级可观测性入口。结合 running 属性与总任务数,即可构建精准、低开销的并发任务仪表盘,无需引入复杂状态管理库,特别适合脚本化、运维类或 CLI 应用的用户体验增强。










