1

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)

Vikram Khemlani
  • 475
  • 5
  • 16
  • 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
  • 1
    You 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 Answers1

2

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
  • 59,538
  • 10
  • 90
  • 129
  • 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
    @VikramKhemlani, Same idea, using object.entries. See edit – danh Nov 14 '19 at 04:41
  • 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
  • 1
    Agree, @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