I am writing in typescript and I have an object with distinct keys, each mapping to a value. I want to iterate over the keys and do an asynchronous function with their value. I know that you can encase .map (to iterate over arrays) in Promise.all, but how can you do it iterating over a for (let i in object) loop? I'm open to other options that allow all keys to be run concurrently, but waiting on all to complete. Edit: I don't want to use Object.keys because I don't want to iterate over the entire objects keys more than once (Object.keys iterates over the objects keys once, and then I will have to iterate for Promise.all)
Asked
Active
Viewed 2,075 times
3
-
Possible duplicate of [Get array of object's keys](https://stackoverflow.com/questions/8763125/get-array-of-objects-keys) – CertainPerformance Nov 14 '19 at 04:25
-
Take the object's keys (or values or whatever) and map each to a Promise, then you can call `Promise.all` – CertainPerformance Nov 14 '19 at 04:26
-
In terms of performance, the object could be very long and I don't want to turn it into an array then iterate over the array. – Vikram Khemlani Nov 14 '19 at 04:26
-
1You could use `for..in` and push each promise generated from each key to an array, but I'd think that `.map` would be more performant (and, more importantly, much more readable) – CertainPerformance Nov 14 '19 at 04:27
-
Turning each into a promise isn't good for performance since I have to iterate over the entire object, I'm trying to avoid doing so. – Vikram Khemlani Nov 14 '19 at 04:28
-
You say you have to *do an asynchronous function with their value*, so it sounds like there's no avoiding that – CertainPerformance Nov 14 '19 at 04:29
-
I see your point. I thought when you run promise.all, each iteration runs concurrently, but I guess I misunderstood – Vikram Khemlani Nov 14 '19 at 04:30
-
Almost nothing *blocks* by default. Everything will run concurrently unless you explicitly wait for something else to complete first. – CertainPerformance Nov 14 '19 at 04:32
-
Yea, I wanted to wait on all the promises to complete though, so I was using await Promise.all. In terms of mapping each key to a promise, how would I be able to do that? would it just be array['key'] = new Promise(resolve, reject => {}) and then doing promise.all(array)? Something like that? – Vikram Khemlani Nov 14 '19 at 04:34
-
Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/202302/discussion-between-vikram-khemlani-and-certainperformance). – Vikram Khemlani Nov 14 '19 at 04:46
1 Answers
3
Object.entries() can get the keys and values. Collect promises for each key-value pair, and fulfill them with all()
.
function asyncFunctionWithKeysAndValuesOf(object) {
let promises = Object.entries(object).map(keyValue => somePromiseReturningFn(keyValue[0], keyValue[1]))
return Promise.all(promises)
}
If you're sensitive to iterating the object more than once...
let promises = []
for (key in object) {
promises.push(somePromiseReturningFn(key, object[key]))
}
return Promise.all(promises)

danh
- 62,181
- 10
- 95
- 136
-
Thanks! But I need the keys and the values, and for performance, I didn't want to use Object. because I didn't want to iterate over the object items more than once. – Vikram Khemlani Nov 14 '19 at 04:40
-
1
-
Ok . Object.entries iterates over the object once, which is something I was trying to avoid, as map will iterate over the object again, but I guess O(2n) isn't so bad and I don't see a way around it. Thanks – Vikram Khemlani Nov 14 '19 at 04:44
-
1Agree, @VikramKhemlani, that it's typically fine to loop twice, but we can do just one loop if you prefer. Just not as pretty. See edit. – danh Nov 14 '19 at 04:50
-
Thanks much! Just fairly new and wanted to make as efficient as possible – Vikram Khemlani Nov 14 '19 at 04:55
-
This looks beautiful, but I can't understand it! Maybe giving an example for `somePromiseReturningFn` – godhar Nov 24 '22 at 15:38
-
@godhar - I just mean anything that runs asynchronously, like a fetch. The idea behind the post is that sometimes objects hold the parameters that you want to use to call an async function, sort of like an async todo list. This pattern maps the those params into a list of promises (and runs them all with promise all) – danh Nov 24 '22 at 16:07
-
What if I have ids, I Object.entries seems to be using indexes. I need to map an id to a request url. Is this possible? – godhar Nov 24 '22 at 16:16
-
Very possible, @godhar. Object entries provides an array of an object's keys and values. Those might look like indexes if the object is an array. Feel free to write a question and paste the link here. – danh Nov 24 '22 at 17:09
-
Thanks, any help would be really apprecitated. https://stackoverflow.com/questions/74564449/mapping-ids-to-promise-all-response-data – godhar Nov 24 '22 at 17:30