4

How to wait for function to finish in JavaScript? I have 2 functions updateSeason and updateFixtures and I want to wait for first one to finish before run next one.

Both my functions are async and they working perfectly fine. Only problem is if I do not use setTimeout I need to run it twice because updateFixture run before updateSeason finish and there is still no file for fucntion to fetch on first run.

updateData

const updateData = async () => {
  await updateSeason();
  await updateFixtures();
};

updateSeason

    // UPDATE SEASON
const updateSeason = async () => {
  // SEASONS TEMPLATE
  let seasonsTemplate = {
    timestamp: new Date(),
    season: null,
    leagues: [],
  };

  // FETCH LEAGUES INFO
  const leagues = await fetch(url + "leagues?subscribed=true&" + key)
    .then((response) => response.json())
    .then((data) => data.data);

  // MAP THROUGH LEAGUES
  leagues.map(async (league) => {
    const id = `${league.league_id}&`;

    // FETCH SEASONS INFO
    const seasons = await fetch(url + "seasons?league_id=" + id + key)
      .then((response) => response.json())
      .then((data) => data.data);

    // MAP THROUGH LEAGUES & POPULATE SEASONS TEMPLATE
    seasons.map((season) => {
      if (season.is_current) {
        seasonsTemplate.season = `${moment(season.start_date).format("YYYY")}_${moment(season.end_date).format("YYYY")}`;
        seasonsTemplate.leagues.push({
          country_id: season.country_id,
          league_id: league.league_id,
          league_name: league.name,
          season_id: season.season_id,
          start_date: season.start_date,
          end_date: season.end_date,
        });
      }
    });

    // CHECK / CREATE SEASON FOLDER
    const currentSeasonFolder = `./data/${seasonsTemplate.season}`;
    if (!existsSync(currentSeasonFolder)) {
      await mkdir(currentSeasonFolder);
      await mkdir(`${currentSeasonFolder}/matches`);
    }

    // CREATE / UPDATE SEASON FILES
    await writeFile("./data/current_season.json", JSON.stringify(seasonsTemplate));
    await writeFile(`${currentSeasonFolder}/season.json`, JSON.stringify(seasonsTemplate));

    console.log(`${league.name} updated...`);
  });
};

updateFixtures

    // UPDATE FIXTURES
    const updateFixtures = async () => {
      // FIXTURES TEMPLATE
      let fixturesTemplate = {
        timestamp: new Date(),
        season: null,
        fixtures: [],
      };
    
      // FETCH CURRENT SEASON INFO
      const season = await fetch(api + "current_season.json").then((response) => response.json());
    
      // POPULATE FIXTURES TEMPLATE SEASON
      fixturesTemplate.season = season.season;
    
      // MAP THROUGH LEAGUES
      season.leagues.map(async (league) => {
        const id = `${league.season_id}&`;
    
        // FETCH COMPETITION FIXTURES
        const fixtures = await fetch(url + "matches?season_id=" + id + key)
          .then((response) => response.json())
          .then((data) => data.data);
    
       

 // MAP THROUGH FIXTURES & POPULATE FIXTURES TEMPLATE
    fixtures.map((match) => {
      if ((match.home_team.team_id === teamId || match.away_team.team_id === teamId) && match.status !== "postponed") {
        fixturesTemplate.fixtures.push({
          match_timestamp: new Date(match.match_start_iso).getTime(),
          match_start: match.match_start_iso,
          match_id: match.match_id,
          status: match.status === "" ? "notstarted" : match.status,
          home_team: getTeamName(match.home_team.team_id),
          home_short: getShortName(match.home_team.team_id),
          away_team: getTeamName(match.away_team.team_id),
          away_short: getShortName(match.away_team.team_id),
        });
      }
    });

    // SORT FIXTURES BY DATE IN ASCENDING ORDER
    fixturesTemplate.fixtures.sort((a, b) => a.match_timestamp - b.match_timestamp);

    // CREATE / UPDATE FIXTURES FILES
    const currentSeasonFolder = `./data/${season.season}`;
    await writeFile(currentSeasonFolder + "/fixtures.json", JSON.stringify(fixturesTemplate));

    console.log("Fixtures updated...");
  });
};

UPDATE:

Issue was inside functions itself. async Array.prototype.map repleaced with for loop in both functions updateSeason and updateFixtures and now is working

1
  • 3
    leagues.map(async (league) => this just fires off a bunch of async calls without awaiting them. Use a traditional for...of loop. stackoverflow.com/questions/37576685/… Commented Apr 29, 2021 at 11:11

4 Answers 4

3

You can just use async/await for your defined functions, even if you cannot use 'await' keyword outside an async function.

So, for example, you have a index.js file, you can do:


async function main() {
  await updateSeason();
  await updateFixtures();
}

main()

or invoking directly the function with the short form


(async function main() {
  await updateSeason();
  await updateFixtures();
})()

Anyway, avoid to use 'writeFileSync' or other 'Sync' functions inside an async function because that block the event loop and decrease your performance.

EDIT: I saw now that you are using Array.prototype.map function with an async callback, that could be the problem.

Try to look here: https://flaviocopes.com/javascript-async-await-array-map/

Or, otherwise, use a standard for loop to handle your leagues

Sign up to request clarification or add additional context in comments.

6 Comments

When I use writeFile and mkdir, functions not working at all, I am getting error then Callback must be a function. Received undefined
Yeah, because since they are async, they need a callback, but you can use fs.promises that work with async/await. Have a look here nodejs.org/api/fs.html#fs_promises_api
I replaced writeFileSync and mkdirSync imported from fs for await writeFile and await mkdirSync imported from fs/promises but I still getting same outcome FetchError on first run. Code updated
Sorry, I can't see the update. Anyway, have a look on my edited reponse regarding using map array function.
I updated my code and replace Array.prototype.map functions with standard for loops and works perfect :)
|
1

Why not just,

async function updateData() {
  await updatedSeason();
  await updateFixtures()
}

updateData();

3 Comments

This is what I done originally and for some reason is not working. I think problem is somewhere inside functions itself
@Klak031 There's an issue with how you're awaiting inside the map function. You're trying to await something that's not a promise. I'll try to update my answer with async mocks in a bit. You'll also need to wrap you map inside a Promise.all
This is proper way of calling async functions and working perfect. Problem was inside functions with Array.prototype.map and async which a change to standard for loop and now working.
0

Async Await can help you out here since they are both async functions.

const updateData = async () => {
  await updateSeason();
  await updateFixtures();
};

1 Comment

This is proper way of calling async functions and working perfect. Problem was inside functions with Array.prototype.map and async which a change to standard for loop and now working.
0

You forgot to put "await" before the function

const updateData = async () => {
  // Add await before the functions because they are async functions
  await updateSeason()       
  await updateFixtures()
};

2 Comments

await needs to be used inside an async function, unless of course top-level await is what the op has.
This is proper way of calling async functions and working perfect. Problem was inside functions with Array.prototype.map and async which a change to standard for loop and now working.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.