javascript 有人能告诉我为什么我的承诺队列不起作用吗?

wd2eg0qa  于 2023-02-15  发布在  Java
关注(0)|答案(2)|浏览(84)

我试图写一个简单的承诺队列函数,该函数将处理50个任务与10个并发承诺:

const sendTasks = () => {
  let tasks = 50;
  const concurrentCount = 10;
  let promisePool = 0;

  while (tasks > 0) {
    console.log(`current tasks: ${tasks}`);
    while (promisePool < concurrentCount && task > 0) {
      console.log("create promise");
      tasks--;
      promisePool++;
      const promise = new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve("haha");
        }, Math.floor(Math.random() * 3) * 1000);
      });

      promise.then((value) => {
        console.log(value);
        promisePool--;
      });

      console.log(`current promisePool: ${promisePool}`);
    }
  }  

  return "done";
};

但是当我执行它的时候,承诺似乎永远不会解决,然后一直停留在task〉0 while循环中,有人能给我解释一下为什么承诺永远不会解决吗?

zphenhs4

zphenhs41#

同步函数内的while循环永远不会向Promise .then或任何其他对象生成控制流。您需要重新调整代码结构,以等待Promise解析,而不会完全终止sendTasks函数,也不会阻塞引擎。
一种方法是将每个Promises推送到一个数组中,然后在该数组上等待Promise.any。当Promises完成时,让它们自己从数组中移除,并递归地将更多的Promises推送到数组中。然后在数组中不再存在Promises时返回。

const sendTasks = async () => {
  let tasks = 50;
  const concurrentCount = 10;
  let promisePool = 0;
  let promises = [];
  const enqueueNext = () => {
    if (!tasks) return;
    // creating this variable just for the sake of logging
    const thisTask = tasks--;
    console.log("create promise", thisTask);
    const prom = new Promise((resolve) => {
      setTimeout(() => {
        promises = promises.filter(p => p !== prom);
        console.log('resolving', thisTask);
        resolve("haha");
        // recursive asynchronous call; init the next promise, if there is one
        enqueueNext();
      }, Math.floor(Math.random() * 3) * 1000);
    });
    promises.push(prom);
  };
  for (let i = 0; i < concurrentCount; i++) {
    enqueueNext();
  }
  while (promises.length) {
    await Promise.any(promises);
  }
  console.log("done");
};
sendTasks();
z31licg0

z31licg02#

JavaScript是单线程的,除非它明确地不是(Web工作者、节点多处理,... -不承诺),所以while (tasks > 0) {是一个忙碌的循环,它永远不会将控制返回给任何事件循环,并给定时器触发的机会。
您需要为您的承诺给予一个函数(.then)或延续(async/await),以便您可以退回到事件循环并被告知何时继续处理。

const sendTasks = async () => {
  let tasks = 50;
  const concurrentCount = 10;
  const promisePool = new Set();

  while (tasks > 0) {
    console.log(`current tasks: ${tasks}`);
    while (promisePool.size < concurrentCount) {
      console.log("create promise");
      tasks--;
      const promise = new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve("haha");
        }, Math.floor(Math.random() * 3) * 1000);
      });

      promise.then((value) => {
        console.log(value);
        promisePool.delete(promise);
      });

      promisePool.add(promise);

      console.log(`current promisePool: ${[...promisePool]}`);
    }
    
    await Promise.race(promisePool);
  }

  // all tasks have been created here, but not necessarily completed
  await Promise.all(promisePool);

  return "done";
};

sendTasks().then(console.log);

相关问题