Promise.all的并发请求

如果有20个Promise,浏览器的并发设置为3,如何保证始终有3个Promise在请求

阅读 2.9k
3 个回答

https://segmentfault.com/a/11...

或者这也是一种:
说一下思路:
1.维护一个任务队列;
2.维护一个并发值;
3.开始的时候同时执行等于并发值的任务;
4.每个任务都是异步的,任务fulfill状态后判断队列里是否有任务&&在执行的任务是否达到并发值,满足条件从任务队列中拿出一个任务执行。

class Scheduler {
            constructor(limit) {
                this.queue = [];
                this.limit = limit;
                this.runCounts = 0;
            }

            add(time, task) {
                const promiseProducer = () => {
                    return new Promise((resolve, reject) => {
                        setTimeout(() => {
                            console.log(task);
                            resolve();
                        }, time);
                    })
                }
                this.queue.push(promiseProducer)
            }

            request() {
                if (this.queue.length && this.runCounts <= this.limit) {
                    this.runCounts++;
                    this.queue.shift()().then(() => {
                        this.runCounts--;
                        this.request();
                    });
                }
            }

            start() {
                for (let i = 0; i < this.limit; i++) {
                    this.request();
                }
            }
        }

        const scheduler = new Scheduler(2);
        const addTask = (time, order) => {
            scheduler.add(time, order);
        };
        addTask(1000, "1");
        addTask(500, "2");
        addTask(300, "3");
        addTask(400, "4");
        scheduler.start();

已参与了 SegmentFault 思否社区 10 周年「问答」打卡 ,欢迎正在阅读的你也加入。

这个人很懒,具体实现只写了20多行代码(娱乐实现,仅供参考).

// 必须先获得锁后释放锁,获得锁和释放锁的次数必须相同,
// 否则会产生未定义行为
class MyLock {
  constructor(
    // 可以进入临界区的最大协程数量
    private N: number
  ) {}

  // 当前被挂起的协程的队列
  private queue: (() => void)[] = []

  // 一个协程在进入临界区之前需要获取一把锁
  async acquire() {
    if (this.N > 0) {
      // 还有剩余的名额,直接返回协程进入临界区,名额减1
      --this.N
    } else {
      // 没有剩余的名额了,在这里返回一个处于pending状态的promise
      // 让协程挂起,并将其放到等待队列中
      return new Promise<void>((resolve) => {
        this.queue.push(resolve)
      })
    }
  }

  async release() {
    if (this.queue.length) {
      // 当前等待队列中有等待的协程,将队列中的第一个协程resume
      this.queue.shift()!()
      return
    }

    // 没有等待的协程,将名额加1
    ++this.N
  }
}

const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))

const tasks = [
  async () => {
    await delay(10000)
    console.log('100')
  },
  async () => {
    await delay(12000)
    console.log('200')
  },
  async () => {
    await delay(2300)
    console.log('300')
  },
  async () => {
    await delay(2400)
    console.log('400')
  },
  async () => {
    await delay(2500)
    console.log('500')
  },
  async () => {
    await delay(2600)
    console.log('600')
  },
  async () => {
    await delay(2700)
    console.log('700')
  },
]
const main = async () => {
  const lock = new MyLock(3)
  for (const task of tasks) {
    await lock.acquire()

    task().then(() => {
      lock.release()
    })
  }
}
main()
推荐问题
宣传栏