Reputation: 398
I have a main function that awaits and connects a few functions in parallel like this:
Main function:
console.log('A');
const pivotData = await Promise.all(
Object.entries(thenWidgets.val()).map(widget => {
getPivot(widget, userId)
console.log('B');
});
);
console.log('C');
console.log('D');
const mainData = await Promise.all(
pivotData.map(widget => getMain(widget))
);
console.log('F');
mainData.map(item => {
return (finalObject[item.widgetId] = item);
});
console.log('G');
The works fine until it hits mainData below console.log('D')
. It seems to not await the promise and skip right to console.log('F')
without waiting for the getMain function which hold console.log('E')
getMain() Function:
const getMain = widget => {
return new Promise(resolve => {
var requests = [];
const pivotData = {};
Object.keys(widget.pivot).map(item => {
const mainRef = firebase
.database()
.ref()
.child(widget['default'].type)
.child(item);
mainRef.once('value', snapMain => {
pivotData[item] = snapMain.val();
}).then(() => {
widget['main'] = pivotData;
console.log('E');
requests.push('test');
});
console.log('E2')
})
Promise.all(requests)
.then(() => {
console.log('E3');
resolve(widget);
})
.catch(error => console.log(`Error in promises ${error}`));
});
};
The expected outcome here is: 'E, E2, E, E2, E3' but what i get is 'E2, E2, E3' and then it returns the promise. Later, somewhere after all the promises have resolved i get 'E, E'. So the expected outcome for the whole thing should be 'A, B, C, D, E, E2, E, E2, E3, F, G' what I have now is 'A, B, C, D, E2, E2, E3, F, G, E, E'
It seems that the promise inside the Object.keys
inside getMain()
is not waiting for the mainRef.once
. Perhaps I am missing something.
My question here is: What is going wrong that the promise is not waiting for the getMain()
function?
Upvotes: 1
Views: 325
Reputation: 411
Let's take a close look at the getMain function, specifically the lines around console.log('E')
. What is happening here is the following:
.once(...)
returns a promise that is not await
-ed so it gets resolved later, after the getMain
has returnedawait
-ed, the next line to execute is console.log('E2')
and then it goes on the next iteration of the looprequests
will be an empty array (because the values were expected to come from the .once(...)
handlers but we never awaited on those promises). Empty array gets resolved immediately, so the Promise.all(requests)
falls through to then
portion, logs out 'E3' and resolves the main promise, effectively returning the original widgetgetMain
returns, the promises that we created earlier will start resolving and modifying the widget "behind the scenes" so the next time you try to do anything with the widget, you may find something completely unexpected.In order to fix this function, you need to await on the promises returned by Firebase before proceeding to the main promise at the bottom - you could do it either by putting the results of .once()
calls into a new array and Promise.all(...)
on that array, or by composing a "chained" promise on each iteration of the loop and then awaiting on it right after the loop
Hope that helps!
Upvotes: 1