用承诺处理数据数组

Processing array of data with promise

我正在寻求有关如何最好地处理以下情况的指导。我对 JS 和异步开发还很陌生,所以我想了解处理这个问题的最佳方法。我将一个 api (callAPI) 称为 returns 项目数组。我需要将这些项目发送给另一个 api (callAPI2),但是 api 没有批量方法,所以我必须为每个项目调用 api大批。下面是我的结构:getArray promise returns 第一个数组,我将数组发送到 promise 2 (getIndividualData),在其中循环并调用第二个 api。我想知道是否有更好的方法来构建它?如果我传入一个大数组,我可能需要调整对 api 的调用速度,这样我就不会受到限制...所以也许我需要某个版本的 Promise.all?

let getArray = function() {
    return new Promise(function(resolve,reject) {
        callApi.get().on('success', function(result, response) {
            resolve(result);
        }); 
    });
}

let getIndividualData = function(arrayOfItems) {
    return new Promise(function(resolve,reject) {
        var responseArray = [];
        for(var i = 0; i < arrayOfItems.length; i++) {
            callApi2.get(arrayOfItems[i]).on('success', function(result, response) {
                responseArray.push(result);
            }); 
        }
        resolve(responseArray);
    });
}

let failureCallback = function() {
    return "Error!";
}

getArray().then(function(response) {
    return getIndividualData(response);
}).then(function(finalArray) {   
    console.log(`The final array is ${JSON.stringify(finalArray)}`);
}).catch(failureCallback);


将其重新表述为一个 helper,该 helper promisify 一个对象,该对象具有 .on('success') 事件处理程序和顶级 .then()ish 代码的异步函数给我们这样的东西...

要调整 API 调用的节奏,请添加 p-limit 或类似于 getIndividualData

function promisifyOnSuccessObj(onSuccessObj) {
  return new Promise((resolve) => {
    onSuccessObj.on("success", (result, response) => resolve(result));
    // TODO: what about `response`?
    // TODO: onSuccessObj.on('error')..?
  });
}

function getIndividualData(arrayOfItems) {
  // Returns an array of promises
  return arrayOfItems.map((item) =>
    promisifyOnSuccessObj(callApi2.get(item)),
  );
}

async function doThings() {
  const result = await promisifyOnSuccessObj(callApi.get());
  const individualDatas = await Promise.all(getIndividualData(result));
  console.log(`The final array is ${JSON.stringify(individualDatas)}`);
}

您可以结合使用 Promise.allmapasync...await 语法,最后根据先前解析的数组承诺得到一组已解析的单个承诺。

const mockApi = {
  request: (response) => {
    return new Promise((resolve, reject) => {
      setTimeout(() => resolve(response), 1000)
    })
  },
  getArray() {
    return this.request(['foo', 'bar', 'baz'])
  },
  getItem(item) {
    return this.request(`Resolved: ${item}`)
  }
}


async function getData() {
  const array = await mockApi.getArray();
  const final = await Promise.all(array.map(e => mockApi.getItem(e)));
  console.log(final)
}

getData()

您可以通过使用承诺集和 async/await 语法实现并发节流器来对大型数组中的每个项目发出请求而不会受到限制。我在下面复制了您的代码,修改了 getIndividualData 的实现并将 concurrency 作为选项传入。

let getArray = function() {
    return new Promise(function(resolve,reject) {
        callApi.get().on('success', function(result, response) {
            resolve(result);
        }); 
    });
}

let getIndividualData = async function(arrayOfItems, { concurrency }) {
  var promiseSet = new Set(),
      responseArray = [],
      i = 0;
  while (i < arrayOfItems.length) {
      if (promiseSet.size >= concurrency) {
          await Promise.race(promiseSet)
      }
      const promise = new Promise(function(resolve,reject) {
          callApi2.get(arrayOfItems[i]).on('success', function(result, response) {
              resolve(result)
          })
      })
      responseArray.push(promise.then(result => {
        promiseSet.delete(promise)
        return result
      }))
      i += 1

  }
  return Promise.all(responseArray)
}

let failureCallback = function() {
    return "Error!";
}


getArray().then(function(response) {
    return getIndividualData(response, { concurrency: 10 });
}).then(function(finalArray) {   
    console.log(`The final array is ${JSON.stringify(finalArray)}`);
}).catch(failureCallback);