用Promise实现带限流的异步爬虫有三种方式:1. Promise.allSettled分批执行,简单可靠但存在空档期;2. async/await加计数器手写限流,响应及时、吞吐稳定;3. 使用p-limit库,轻量健壮、生产推荐。

用 Promise 实现带限流的异步爬虫,核心是控制并发请求数量,避免被目标服务器拒绝或触发风控。关键不是“全量发起再 await”,而是让最多 N 个请求同时进行,有完成就补上新请求。
用 Promise.allSettled + 队列分批执行
适合 URL 数量明确、希望按固定并发数(如 5)稳定发出请求的场景。原理是把所有 URL 切成大小为 N 的批次,每批用 Promise.allSettled 并发执行,等整批结束再处理下一批。
- 简单可靠,不依赖额外库,错误不会中断整个流程
- 缺点是存在“空档期”:某批里一个请求耗时很长,其余已完成的也要干等它结束
- 示例:100 个 URL,N=5 → 分 20 批,每批最多 5 个并发
用 async/await + 运行中计数器(轻量手写限流)
更紧凑的实现方式:维护一个 running = 0 计数器和一个待执行队列,每次调用爬取函数时先判断是否已达上限;没达上限就立即执行并递增计数器,执行完再递减并尝试启动下一个。
- 无需分批,响应更及时——一个请求结束立刻拉起新请求,吞吐更稳
- 注意要用 try/finally 确保计数器一定减少,否则会“卡死”
- 可封装成通用函数,例如:
limitRun(async () => fetch(url), 3)
用 p-limit 库(推荐用于生产)
p-limit 是专门解决这类问题的小而健壮的 npm 包(仅 1KB)。它返回一个 limit 函数,调用它传入异步操作,自动排队、限流、返回 Promise。
立即学习“Java免费学习笔记(深入)”;
- 一行创建限流器:
const limit = pLimit(3) - 安全调度:
limit(() => fetch(url).then(r => r.json())) - 内部已处理错误、取消、高负载下的稳定性,比手写更省心
补充:配合重试与基础防屏蔽
限流只是第一步。真实爬虫还需叠加简单防护策略,否则仍易失败:
- 每个请求加随机延迟(如 300–1200ms),避免规律性请求
- 设置合理的 User-Agent 和 headers(如 Accept、Accept-Language)
- 对 429/503 响应做指数退避重试(最多 2–3 次),别直接 throw
- 避免高频访问同一路径,必要时加域名级并发隔离(如每域名最多 2 并发)


















