0

I've been trying to read about async functions and promises all day but I can't seem to wrap my head around retreiving the data in my example.

I have the following async function that iterates through some database values and appends them to an array which it returns:

async function userMemberships (){
var membershipsList = [];
onAuthStateChanged(auth, user => {
    if(user){
        var i= 0;
        var refInstanceMemberships = ref(db, 'instance-memberships/');
        onValue(refInstanceMemberships, (instanceMembershipsSnap) => {
            instanceMembershipsSnap.forEach((instanceSnap) => {
                instanceSnap.forEach((userSnap) => {
                    if(userSnap.key == user.uid){
                        membershipsList.push(
                            {instanceId: userSnap.ref.parent.key}
                            //userSnap.ref.parent.key
                            )
                        //appendToInstanceList(userSnap.ref.parent.key)
                    }
                })
            })
        }, {
            onlyOnce: true
        })
    } else{
        console.log('Not logged in...');
    }
});
return membershipsList
}

From what I understand, because this is an async function, it is going to return a promise, and for me to get the array values I need to call this function from another async function along with 'await'. so I have the following function which does that:

async function getMemberships() {
  const memberships = await userMemberships();
  console.log(memberships)                     //Returns an array in the console log. Expected
  console.log(memberships.length)              //Returns 0. Unexpected
  console.log(memberships[0])                  //Returns undefined. Unexpected
}

This function is called using:

(async () => {await getMemberships()})();

I'm obviously missing something about async functions, because I thought that console.log(memberships.length) would run after const memberships had been populated, especially considering console.log(memberships) did. Would anybody be able to try to explain this to me?

Josh
  • 19
  • 5
  • 2
    `I'm obviously missing something about async functions,` Yes, async functions are wrappers for promises, not wrappers for functions that take callbacks. You will want to use Promise constructor to make your function into a promise. – Keith Oct 12 '22 at 16:20
  • 2
    There's no point to an `async` function that doesn't use `await`. The purpose of [`async` functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) is to provide more convenient syntax ("syntactic sugar") for creating and consuming [promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises). Your function doesn't create or consume promises. If you want to wrap that callback-based API in a promise, [here's how to do that](https://stackoverflow.com/questions/22519784/how-do-i-convert-an-existing-callback-api-to-promises). – T.J. Crowder Oct 12 '22 at 16:21
  • 1
    Also note that console logging is *not* synchronous. It *schedules* a log action, and by the time that actually happens, even if only 1ms later, the array you're logging may have different content, because you're asynchronously updating it. You won't see the thing "as it is on that line of code" unless you force that (e.g by slicing the array) – Mike 'Pomax' Kamermans Oct 12 '22 at 16:41
  • Thanks for the help everyone, I think I've got an idea how this works now. I hadn't fully understood what the purpose of 'async' in a function was doing. The `onAuthStateChanged` function using callbacks is asynchronous by itself without the async function. And when `return membershipsList` was called, it was outside the callback so it was executed before the array was populated in the callback. Is that all correct? – Josh Oct 12 '22 at 17:17
  • @Josh Yes, exactly, `userMemberships` didn't wait for `onAuthStateChanged` – Bergi Oct 12 '22 at 21:22

0 Answers0