Skip to content
Advertisement

Order of Async function calls

I’m making a React App for my Football team to keep track of Payments and Debts for each Member. I’m trying to search the database for Records for each Season and delete a Member if no records are found. Currently the Member gets deleted then the database searched.

This is the code block (it can also be seen with the rest of my App on GitHub here). I use Firebase to store all my data.

import database from '../firebase/firebase';

export const startRemoveMember = ( playerUuid, seasonList ) => 
{
    return (dispatch, getState) =>
    {
        let canDelete = true;
        const uid = getState().auth.uid;

        // This should resolve first
        seasonList.forEach( (season) =>
        {
            database.ref(`subs-tracker/users/${uid}/debts_and_payments/${season.seasonUuid}`)
                .once('value')
                .then((records) =>
                {
                    records.forEach((childRecord) =>
                    {
                        if(childRecord.val().playerUuid === playerUuid)
                        {
                            canDelete = false;
                            return true; // breaks loop if record is found
                        };
                    });
                });
        });

        // This resolves first before block above
        if(canDelete)
        {
            alert('Deleted');
            return database.ref(`subs-tracker/users/${uid}/members/${playerUuid}`)
                .remove()
                .then((ref) =>
                {
                    dispatch(removeMember(playerUuid)); // Calls removeMember() function to remove the Member from the State of the App
                })
        }
        else
        {
            alert('Cannot Delete. Member has records');
            return false;
        }
    };
};

I’m probably missing something basic. I’m no expert with Databases and Async calls. Any help you would be appreciated 🙂

Advertisement

Answer

In your outer forEach callback you are creating a promise in each iteration. All those promises must resolve first.

You’ll have to await all of them.

So instead of doing forEach, use map so you can collect those promises in an array. Then call Promise.all on those, so you have a promise that will resolve when all those have resolved. Then put the deletion code inside a then callback. It cannot obviously be executed synchronously.

This also means you have to think about the return value of your (dispatch, getState) => function. That function cannot give an indication of success in a synchronous way. So it should best return a promise as well.

        const promises = seasonList.map( (season) =>
            database.ref(`subs-tracker/users/${uid}/debts_and_payments/${season.seasonUuid}`)
                .once('value')
                .then((records) =>
                    records.forEach((childRecord) => // breaks on true
                        childRecord.val().playerUuid === playerUuid
                    );
                );
        );

        return Promise.all(promises).then(findings =>
            findings.includes(true)
        ).then(cannotDelete => {
            if (cannotDelete) {
                alert('Cannot Delete. Member has records');
                return false;
            } else {
                alert('Deleted');
                return database.ref(`subs-tracker/users/${uid}/members/${playerUuid}`)
                    .remove()
                    .then((ref) => {
                        dispatch(removeMember(playerUuid)); // Calls removeMember() function to remove the Member from the State of the App
                        return true; // To distinguish from false
                    });
            }
        });
User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement