Anudeep Ananth
Anudeep Ananth

Reputation: 1123

Async function in Firebase resolves the promise even before the function body has finished executing

So I have an async function which takes an array of custom objects as an argument, then loop through each of those objects and get some data from the firestore. The data from Firestore is converted to another custom object and added to another to an array of custom objects. The length of these objects is returned by the function.

async function getCompsReceived(theInterestedPeople: InterestedPerson[]) {

  const whatsNewObjects: WhatsNewObject[] = []

  theInterestedPeople.forEach(async (person) => {

    const documentsSnapshot = await 
    db.collection('Users').doc(person.uid).collection('complimentsReceived')
      .orderBy('receivedTime', 'desc')
      .limit(documentLimit)
      .get()

  if (documentsSnapshot.empty) {
    console.log(`${person.userName} has no compsReceived`)
    return
  }


  await documentsSnapshot.forEach((newCompReceived: { receiverUid: string; receiverUserName: string; 
    complimentsReceivedContent: string | null; hasImage: boolean | null; senderUid: string | null; 
      senderUserName: string | null; noOfLikes: number | null; receivedTime: number | null; 
        complimentId: string | null} ) => {
         //Add each new Compliment to the WhatsNewObjects Array
         const whatsNewDoc = new WhatsNewObject(
           newCompReceived.receiverUid,
           newCompReceived.receiverUserName,
           true,
           newCompReceived.complimentsReceivedContent,
           newCompReceived.hasImage,
           newCompReceived.senderUid,
           newCompReceived.senderUserName,
           newCompReceived.noOfLikes,
           newCompReceived.receivedTime,
           newCompReceived.complimentId,
           'PERSON_COMPLIMENT_RECEIVED'
         )

    whatsNewObjects.push(whatsNewDoc)

  })

  console.log(`length of whatsNewObjects after adding ${person.userName}'s compsReceived is      
    ${whatsNewObjects.length}`)

})

console.log(`returning the length of WhatsNewObjects at getCompsReceived which is ${whatsNewObjects.length}}`)
    return whatsNewObjects.length

}

The problem is this function always returns 0 and with the log statements printed at Firebase console, I see that the body of the function is being executed after the function has already returned a value which is a Promise of type number.

Can someone help me in How do I make the function wait for the body to be executed before returning the whatsNewObjects.length ?

Upvotes: 0

Views: 269

Answers (2)

The problem is related to forEach it actually run async even if you use async/await in callback function . You can solve this problem by simply changing forEach to any kind of for iterators.

for (let index = 0; index < theInterestedPeople.length; index++) {
    const person = array[index];
    ....your code
}
// or
for (const person of theInterestedPeople) {
    
}
// or

Upvotes: 1

Christian
Christian

Reputation: 7862

You shouldn't use forEach for iterating async code since it doesn't await. It will just fire-and-forget. Use for..ofinstead:

async function getCompsReceived(theInterestedPeople: InterestedPerson[]) {

    const whatsNewObjects: WhatsNewObject[] = []

    for (const person of theInterestedPeople) {
        const documentsSnapshot = await db.collection('Users').doc(person.uid).collection('complimentsReceived')
            .orderBy('receivedTime', 'desc')
            .limit(documentLimit)
            .get();

        if (documentsSnapshot.empty) {
            console.log(`${person.userName} has no compsReceived`)
            return;
        }

        documentsSnapshot.forEach((newCompReceived: {
            receiverUid: string; receiverUserName: string;
            complimentsReceivedContent: string | null; hasImage: boolean | null; senderUid: string | null;
            senderUserName: string | null; noOfLikes: number | null; receivedTime: number | null;
            complimentId: string | null
        }) => {
            //Add each new Compliment to the WhatsNewObjects Array
            const whatsNewDoc = new WhatsNewObject(
                newCompReceived.receiverUid,
                newCompReceived.receiverUserName,
                true,
                newCompReceived.complimentsReceivedContent,
                newCompReceived.hasImage,
                newCompReceived.senderUid,
                newCompReceived.senderUserName,
                newCompReceived.noOfLikes,
                newCompReceived.receivedTime,
                newCompReceived.complimentId,
                'PERSON_COMPLIMENT_RECEIVED'
            );
            whatsNewObjects.push(whatsNewDoc);

        })
        console.log(`length of whatsNewObjects after adding ${person.userName}'s compsReceived is ${whatsNewObjects.length}`);
    }
    console.log(`returning the length of WhatsNewObjects at getCompsReceived which is ${whatsNewObjects.length}}`);
    return whatsNewObjects.length;
}

Upvotes: 2

Related Questions