javascript 如何在一个对象数组上使用Promise.all,然后将它们重新分配给新对象中的相关键?

ohtdti5x  于 2023-04-19  发布在  Java
关注(0)|答案(3)|浏览(70)

此问题已在此处有答案

How to use Promise.all with an object as input(17回答)
4年前关闭。
我在代码的中间部分有点卡住了。我知道我想要的结尾和开头是什么样子的,但似乎无法填补空白。
我在4个API端点上调用fetch,并将Promises存储到一个相关的键中,告诉我它们是什么。
然后我使用for in循环遍历所有这些,并将所有这些Promises放入一个数组中,以便我可以对它们调用Promise.all
在成功地将数组记录到控制台之后,我现在看到数组中充满了带有我的数据的对象。但是,我没有办法告诉哪些数据属于哪个对象键,就像在原始对象中一样
有更好的方法吗?我确实知道我想在这段代码中使用Promise.all;这是我不想让步的事情,因为我正在试图弄清楚我如何才能在不放弃的情况下实现这一目标(现在已经有几个小时了)。
在我的代码的最后(这只是我的React应用程序中一个真实的例子的伪代码),我只想把最后一个对象推送到state中。
任何帮助都很感激。

//imitating React State as an example
const state = {
  iliakan: '',
  remy: '',
  jeresig: '',
}

//put all of the urls in an object with a key-pair value to describe the data
const githubAPI = {
  iliakan: 'https://api.github.com/users/iliakan',
  remy: 'https://api.github.com/users/remy',
  jeresig: 'https://api.github.com/users/jeresig'
}

//create an empty object to assign promises to keys
const movieData = {};
const promiseArr = [];
//store promise into relevant key
for (const user in githubAPI) {
  movieData[user] = fetch().then(res => res.json())
}
//now movieData has keys with values set to related Promises
console.log(movieData);
//loop through these promises, and put them in an Array for Promise.all
for (const userData in movieData) {
  promiseArr.push(movieData[userData])
}

//Use Promise.all on all of those promises
Promise.all(promiseArr).then(responseArr => console.log(responseArr);

//this is where I am stuck. I now have an array of objects with all the correct data, but I don't know how to reassign them back to their original, matching key that they had in the movieData object!


//end goal is to have an object like this
//const movieData = {
//  iliakan: {//object with data from api},
//  remy: {//object with data from api},
//  jeresig: {//object with data from api}
//}

//use the movieData to setState and update current component state
syqv5f0l

syqv5f0l1#

一种方法是将“键和属性之间的连接”视为编程中自己的“事物”:一个键-值对。javascript API将它们称为“条目”,并使用一个简单的2元素数组作为“事物”:['key', 'value']key: 'value'
你可以使用Object.entries(the_object)从一个对象到条目。它将返回一个数组,其中包含“entry-array”-s:

const githubAPI = {
  iliakan: 'https://api.github.com/users/iliakan',
  remy: 'https://api.github.com/users/remy',
  jeresig: 'https://api.github.com/users/jeresig'
}

let githubEntries = Object.entries(githubAPI)
// githubEntries = [
//   ['iliakan', 'https://api.github.com/users/iliakan'],
//   ['remy', 'https://api.github.com/users/remy'],
//   ['jeresig', 'https://api.github.com/users/jeresig'],
// ]

现在你可以使用这个概念,并使promise也成为“条目”,结果和键组合在一个[key, value]数组中。这样,你可以稍后从Promise.all结果中的条目重建对象。

let promiseOfEntries = Promise.all(Object.entries(githubAPI).map((entry) => {
  let [key, value] = entry;
  return fetch().then(x => x.json()).then(result => {
    // Important step here: We combine the result with the key,
    // into a new [key, value] entry
    return [key, result];
  })
}

let promiseOfResults = promiseOfEntries.then(resultEntries => {
  // From the "entries", we build an object again here
  let results = {};
  for (let [key, value] of resultEntries) {
    results[key] = value;
  }
  return results;
});

promiseOfResults.then(results => {
  // Do anything with results!
  console.log('results:', results);
});

Lodash甚至有_.fromPairs来完成[ [key, value], [key2, value2], ...]{ key: value, key2: value2 }的转换。https://lodash.com/docs/4.17.11#fromPairs
您可以在任何需要在对象和数组之间切换的地方使用“条目”的概念。
希望我解释得足够好,如果我没有,不要害怕在评论中提出问题!

vs3odd8k

vs3odd8k2#

你只需要将键Map到匹配的数组索引。这就是你所缺少的:

const orderOfKeys = [] // create a helper Array

for (const userData in movieData) {
  promiseArr.push(movieData[userData])
  orderOfKeys.push(userData) // Memoize the keys, now the index matches the proper key
}

//Use Promise.all on all of those promises
Promise.all(promiseArr).then(responseArr => {
  const movieData = {}

  for (let i = 0; i < responseArr.length; i++) {
    movieData[orderOfKeys[i]] = responseArr[i]
  }

  console.log(movieData) // bingo
});

下面是一个替换for循环的代码行:

const movieData = responseArr.reduce((mD, response, index) => ({ ...mD, [orderOfKeys[index]]: response }), {})
wxclj1h5

wxclj1h53#

尝试下面的方法,创建一个键数组,它将跟踪promise的顺序,并允许您知道哪个“用户”与每个promise相关联。然后您可以正确设置movieData对象。

const movieData = {};
// Added keyTracker array declaration here...
const promiseArr = [], keyTracker = [];
for (const user in githubAPI) {
  movieData[user] = fetch().then(res => res.json())
}
console.log(movieData);
for (const user in movieData) {
  // Track the order of the promises by saving the key in our keyTracker
  keyTracker.push(user);
  promiseArr.push(movieData[user]);
}

Promise.all(promiseArr).then(responseArr => console.log(responseArr));

// Now we have a lookup for the keys (keyTracker) that will allow us to 
// set the movieData correctly.
keyTracker.forEach((key, idx) => {
  movieData[key] = promiseArr[idx];
});

相关问题