I trying to create a dictionary of dictionaries. Each item in the dictionary is assigned asynchronously. I would like to wait until all items are assigned before printing the result to the console.
Program
const dict = {};
async function placeholder (letter, number) {
await new Promise(r => setTimeout(r, 2000));
return 'test';
}
async function secondMethod (letter, number) {
try {
dict[letter][number] = await placeholder (letter, number);
}
catch (err) {
console.error(err)
}
}
async function firstMethod (letter) {
dict[letter] = {};
const numbers = ['1', '2', '3', '4'];
await numbers.forEach (number => secondMethod (letter, number));
}
async function main () {
const letters = ['a', 'b', 'c', 'd'];
await letters.forEach (letter => firstMethod (letter));
console.log (dict)
};
main ();
Result
{ a: {}, b: {}, c: {}, d: {} }
Desired Result
{
a: { '1': 'test', '2': 'test', '3': 'test', '4': 'test' },
b: { '1': 'test', '2': 'test', '3': 'test', '4': 'test' },
c: { '1': 'test', '2': 'test', '3': 'test', '4': 'test' },
d: { '1': 'test', '2': 'test', '3': 'test', '4': 'test' }
}
CodePudding user response:
The problem is that Array.forEach
is a synchronous function, you cannot call await
on it. You'll need to restructure your code flow to use proper async loops to reach the desired result.
Using the await in every single call:
const dict = {};
async function placeholder(letter, number) {
await new Promise(r => setTimeout(r, 200));
return 'test';
}
async function secondMethod(letter, number) {
try {
dict[letter][number] = await placeholder (letter, number);
}
catch (err) {
console.error(err)
}
}
async function firstMethod(letter) {
dict[letter] = {};
const numbers = ['1', '2', '3', '4'];
for (const number of numbers) {
await secondMethod (letter, number);
}
}
async function main() {
const letters = ['a', 'b', 'c', 'd'];
for (const letter of letters) {
await firstMethod(letter);
}
console.log(dict)
// pretty html result
let resultContainer = document.getElementById("result")
resultContainer.innerHTML = JSON.stringify(dict, null, 2)
};
main();
<h2> Result: </h2>
<pre id="result">Waiting results...</pre>
Using promise.all to have all the promises execute in "parallel"
const dict = {};
async function placeholder(letter, number) {
await new Promise(r => setTimeout(r, 200));
return 'test';
}
async function secondMethod(letter, number) {
try {
dict[letter][number] = await placeholder (letter, number);
}
catch (err) {
console.error(err)
}
}
async function firstMethod(letter) {
dict[letter] = {};
const numbers = ['1', '2', '3', '4'];
const promises = [];
for (const number of numbers) {
promises.push(secondMethod (letter, number));
}
await Promise.all(promises);
}
async function main() {
const letters = ['a', 'b', 'c', 'd'];
const promises = [];
for (const letter of letters) {
promises.push(firstMethod(letter));
}
await Promise.all(promises);
console.log(dict);
// pretty html result
let resultContainer = document.getElementById("result")
resultContainer.innerHTML = JSON.stringify(dict, null, 2)
};
main();
<h2> Result: </h2>
<pre id="result">Waiting results...</pre>
CodePudding user response:
I think this should solve it for you.
async function firstMethod (letter) {
dict[letter] = {};
const numbers = ['1', '2', '3', '4'];
await numbers.forEach(async function (number) {
return await secondMethod(letter, number);
});
}
async function main () {
const letters = ['a', 'b', 'c', 'd'];
await letters.forEach(async function (letter) {
return await firstMethod(letter);
});
console.log (dict);
}