3

There is a question about for await ... of loop.

I have the following code:

    for await (let V of reagentItems.map(objectElement => getPricing(objectElement))) {
       console.log(objectElement) //I'd like to have access to the current iteration.
       //or
       console.log(reagentItems[i]) //current fulfilled element from reagent.map
    }

So the problem is that this array (from .map) of functions (V as a single response of getPricing) doesn't return the objectElement itself but I need to have access to this objectElement inside for await ... of loop.

Does it possible somehow or not? And if it doesn't, using of Promise.all handles this problem somehow? Or I should modify the original getPricing and return current objectElement with other results?

AlexZeDim
  • 3,520
  • 2
  • 28
  • 64
  • 1
    I'd recommend you split the question into the actual two questions it contains. – fjc Apr 19 '20 at 15:08
  • What exactly does `getPricing` return? A Promise? – fjc Apr 19 '20 at 15:13
  • an object like {item_id: Number, price: Number, ... } but this data from this object received via `async/await` functions, and `getPricing` doesn't return the `object_element` itself. So the question is all about: «Can I access the current_executed element/index from `Array` of functions» – AlexZeDim Apr 19 '20 at 15:15

2 Answers2

1

From what I can understand from your question and your comments, you want to be able to access both object_element and the result of getPricing(object_element) within the for loop.

Your problem right now is that as a result of map, you only have the result of getPricing, but not the original object_element. As a solution, simply return both from map in an object:

// just a random getPricing function
function getPricing(objectElement) {
    return {
        item_id: objectElement.id,
        price: Math.random()
    };
}

const reagent_items = [
    {
        id: 'a'
    },
    {
        id: 'b'
    }
];

for (let V of reagent_items.map(object_element => ({object_element, pricing: getPricing(object_element)}))) {
    console.log(`object_element: ${JSON.stringify(V.object_element)}, pricing: ${JSON.stringify(V.pricing)}`);
}
fjc
  • 5,590
  • 17
  • 36
  • Seems that I should combine `.map` method with `Promise.all` as @Bergi mentioned above, but I also grateful to you, for noticing the question format and provided answer. – AlexZeDim Apr 19 '20 at 15:24
0

You should not be using for await here at all - that is meant for asynchronous generators. Instead, do

for (const object_element of reagent_items) {
    const V = await getPricing(object_element);
    console.log(object_element, V)
    …
}

With Promise.all, the code would look like this:

Promise.all(reagent_items.map(object_element =>
    getPricing(object_element).then(V => {
        console.log(object_element, V);
        …
    })
)).then(…)

// or:

await Promise.all(reagent_items.map(async object_element => {
    const V = await getPricing(object_element)
    console.log(object_element, V);
    …
}));
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • And what should I do, if I haven't option to request `getPricing` one-by-one, because `reagent_items` could consist 30+ reagents, which will lead to 30s execution instead of 30 parallel requests, executed in 1s? – AlexZeDim Apr 19 '20 at 15:19
  • 1
    @AlexZeDim for concurrent requests, use `Promise.all` – Bergi Apr 19 '20 at 15:21
  • Well, yeah you right, `Promise.all` would be perfect solution here, because I can chain the result. – AlexZeDim Apr 19 '20 at 15:22