Bootstrap

【JS】Promise 的并发数控制

写爬虫的时候,可能需要控制网络请求的并发数以避免被反爬。我们知道 Promise 的结果是异步获取的,因此控制 Promise 的并发数的基本思路是

  1. 限制最大的并发数
  2. 在最大并发数内启动尽可能多的异步任务
  3. 通过 Promise 队列保存所有异步任务

先从最基本的情况开始——限制并发数为 1,也就是只有前一个 Promise 执行完成后下一个 Promise 才能执行。

// task 中的每一项都是一个返回 Promise 的函数
// 执行 task 的函数其实就是启动异步任务
// e.g.:
// function req = () => {
//  return fetch(url, ...)
// }
const tasks = []

const limit = () => {
	// 任务队列空,退出
	if(!tasks.length) {
		return ;
	}
    // 从队头取数据
	const task = tasks.shift()
	// task 执行完成后,递归
	task().then(() => {
		limit()
	})
}

通过 .then 递归的执行异步任务,我们实现了限制并发数为 1 时的并发控制。

对于并发数 > 1 的情况,特殊的点在于初始化时需要先启动数量 <= 并发数的任务,之后继续进行递归。

const tasks = []
let max_limit = 3

const limit = () => {
	// 任务队列空,退出
	if(!tasks.length || max_limit <= 0) {
		return ;
	}
	
	while(max_limit) {
		// 最大并发数 - 1
		max_limit--;
	    // 从队头取数据
		const task = tasks.shift()
		// task 执行完成后,递归
		task().then(() => {
			// 最大递归数 + 1
			max_limit++
			limit()
		})
	}
}

上述代码通过定义了一个全局变量 max_limit 控制并发数,实际应用中可以用闭包或者类等方法将 max_limit 控制在参数中,以减少耦合。

;