Eric Ahn
Eric Ahn

Reputation: 401

Function is running asynchronously when it shouldn't

I'm implementing some function in which retrieves some data of type array from firebase, then search for specific element from that array and if exists, I would like to abort the function and return back to the caller. (React-native app)

here is the Code:

ref.get().then(snapshot => {
    const personArr = snapshot.data().winPerson;

    ...

    if (personArr != undefined) {
      personArr.forEach(item => {
        if (item == uid.uid) {
          alert(`already subscribed`);
          return;
        }
      });

      if (prop.first.length != 0) {
        uploadHelper(ref, prop, "first");
      }

     ...
    }
});

I loop through the array using forEach and see if there is matching element. If there is match, then it should alert and return to the caller function without running the subsequent code below, which is

if (prop.first.length != 0) {
        uploadHelper(ref, prop, "first");
      }

However, assuming that the element does exist in the array, the code runs both alert and the uploadHelper function(checked through log). First I thought forEach was async function so uploadHelper executed before the return; however, forEach is not async function (after some googling).

I have no idea why uploadHelper runs if the code falls into the if (item == uid.uid) condition and returns.

any help is appreciated. Thank you

Upvotes: 1

Views: 84

Answers (4)

TigerBear
TigerBear

Reputation: 2824

It is returning to the caller function :) a forEach() is calling a function with each element. So you are returning, but only from the function of that one element.

I think a for of loop would be want you want here. People who want to do functional programming want to use the .forEach, but using a for of achieves the same functional effect as a .forEach (don't have to index, no side effect) and is probably more straightforward to use. (a forEach also has an issue if wanting to write async code where you would like to wait between each element)

So, rewrite your code like:

for (const item of personArr) {
    if (item == uid.uid) {
      alert(`already subscribed`);
      return;
    }
  }

Upvotes: 2

Shilly
Shilly

Reputation: 8589

The forEach handler is also a function. ( item => ... is an arrow function ) So returning from inside personArr.forEach() does not actually stop the rest of the function from executing.

So if (prop.first.length != 0) will get checked, no matter what the .forEach() does.

If the goal is to only run uploadHelper when uid is not found, you need to change the structure a little bit. Something like:

ref.get().then(snapshot => {
    const personArr = snapshot.data().winPerson;

    ...

    if (personArr != undefined) {
      const match = personArr.find( item => item === uid.uid );
      if ( match ) alert(`already subscribed`);
      else if (prop.first.length != 0) {
        uploadHelper(ref, prop, "first");
      }
      // else { /* some other defualt case ? */ 
     ...
    }
});

If item is actually the same value as uid.uid, you can even do it simpler:

personArr.includes( uid.uid ) should return true, if uid.uid is inside personArr.

Upvotes: 1

William Gunawan
William Gunawan

Reputation: 750

Use this instead

for (let item of personArr) {
    if (item == uid.uid) {
        alert(`already subscribed`);
        break;
    }
}

forEach is not possible to break, thats why you need to use for instead and break it. in forEach return means continue to next index without processing below code not stop the loop

Upvotes: 1

EnriqueDev
EnriqueDev

Reputation: 1247

First of all, you can't stop a forEach. It will always run for every element of the array and then continue the execution of the code. The return indicates that the element you are iteration on at the moment will be changed for your return value.

If you want to stop the execution you could use a for-in loop or a generic for loop.

Upvotes: 1

Related Questions