如何在 p-limit 中实时监控并发任务进度并显示剩余请求数

1次阅读

如何在 p-limit 中实时监控并发任务进度并显示剩余请求数

本文详解如何利用 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 应用的用户体验增强。

text=ZqhQzanResources