标签导航:

javascript并发控制下如何依次获取所有异步任务的结果?

JavaScript并发控制与异步结果的顺序获取

本文探讨在JavaScript并发控制函数中,如何确保依次获取所有异步任务结果的问题。 问题根源在于原代码中,并发控制函数虽然限制了并发任务数量,但由于Promise的resolve和reject函数被错误地共享,导致后续异步任务的结果无法正确传递。

原代码中createPool函数试图限制并发,但for循环内的fetchData(i).then(...)部分使用了同一个Promise的resolve和reject,使得后来的异步任务无法将结果正确传递到相应的then函数。 由于for循环快速执行,创建了大量Promise实例,但因并发限制,只有前几个Promise能及时执行,其余实例的resolve和reject函数被覆盖,导致仅能获取部分结果。

解决方案是为每个异步任务创建一个唯一的Promise实例,并关联其对应的resolve和reject函数。改进后的代码如下:

const createPool = (task, { concurrency } = {}) => {
  let runningCount = 0;
  const pool = [];
  const promiseMap = new Map();

  return function (i) {
    return new Promise((resolve, reject) => {
      promiseMap.set(i, { resolve, reject });
      pool.push(() => task(i));

      function run() {
        while (pool.length && runningCount < concurrency) {
          runningCount++;
          pool.shift()()
            .then((val) => {
              const { resolve } = promiseMap.get(val);
              resolve(val);
            })
            .catch((e) => reject(e))
            .finally(() => {
              runningCount--;
              run();
            });
        }
      }
      run();
    });
  };
};

改进后的createPool函数使用Map对象promiseMap存储每个任务的Promise实例及其对应的resolve和reject函数。 这样,每个异步任务都能正确地将结果传递到对应的then函数。promiseMap使用任务ID (即i)作为键,方便后续根据ID获取对应的resolve函数。 then方法中,通过promiseMap.get(val)获取对应的resolve函数,确保每个任务的结果都被正确处理。

此修改确保每个fetchData(i)调用都返回一个独立的Promise,从而保证每个任务的结果都能被正确记录和处理,从而解决异步任务结果丢失的问题,并保证结果的顺序性。