Architecd
Architecd

Reputation: 63

How to execute these functions after one another / after one is fully done?

I've got the following function, which doesn't execute in the order I'd like it to.

The console.log within the callback actually gets fired before the loop within the function itself even executes. So to sum it up I'd like the function "getFiles" to fully finish before the next one "createDatabase" starts to execute.

Thanks for your help. I'm already going nuts about this issue :(

const fs = require("fs")
let data = []

const getFiles = () => {
  fs.readdir("./database/test/", (err, files) => {
    files.forEach(file => {
      require("../database/test/" + file)
      data.push(Number(file.split(".")[0]))
      console.log(data)
    })
  })
}

const createDatabase = () => {
  data.sort((a, b) => {
    return a-b
  })
  console.log(data)
  // Do some other stuff
}


const run = async () => {
  await getFiles
  await createDatabase()
  process.exitCode = 0
}

run()

Upvotes: 0

Views: 408

Answers (4)

Ashish Modi
Ashish Modi

Reputation: 7770

I am not really sure what exactly you are trying to do but looks like the problem is in your run function. You are not calling getFiles function inside run. You care just mentioning the function name. Also needs to wrap the getFiles in promise it should be

const run = async () => {
  await getFiles();
  await createDatabase();
  process.exitCode = 0
}

Upvotes: -1

jfriend00
jfriend00

Reputation: 707976

This would be fairly straightforward to code with the newer fs.promises interface so you can await the readdir() output:

const fsp = require('fs').promises;
const path = require('path');

const async getFiles = () => {
  const root = "./database/test/";
  let files = await fsp.readdir(root);
  return files.map(file => {
      require(path.join(root, file));
      return Number(file.split(".")[0]);
  });
}

const createDatabase = (data) => {
  data.sort((a, b) => {
    return a-b
  })
  console.log(data)
  // Do some other stuff
}

const run = async () => {
  let data = await getFiles();
  createDatabase(data);
  process.exitCode = 0
}

run().then(() => {
    console.log("all done");
}).catch(err => {
    console.log(err);
});

Summary of Changes:

  1. Use fs.promises interface so we can await the results of readdir().
  2. Change getFiles() to be async so we can use await and so it returns a promise that is resolved when all the asynchronous work is done.
  3. Move data into the functions (resolved from getFiles() and passed to createDatabase()) rather than being a top level variable that is shared by multiple functions.
  4. Track completion and errors from calling run()
  5. Actually call getFiles() with parens after it in run().

Upvotes: 2

Satvik Daga
Satvik Daga

Reputation: 156

Following code snippet will first completely run getFiles function and then run the createDatabase function. For using async/await, a function needs to return a promise(Read about promises here).

const fs = require("fs")
let data = []

const getFiles = () => {
  return new Promise((resolve, reject) => {
    fs.readdir("./database/test/", (err, files) => {
      if (err) {
        reject(err);
      }
      files.forEach(file => {
        require("../database/test/" + file)
        data.push(Number(file.split(".")[0]))
        console.log(data)
      })
      resolve(true);
    })
  })
}

const createDatabase = () => {
  data.sort((a, b) => {
    return a-b
  })
  console.log(data)
  // Do some other stuff
}


const run = async () => {
  await getFiles();
  await createDatabase();
  process.exitCode = 0;
}

run()

Since the createDatabase function is not returning any promise right now, you can remove await in front of it. Await is used only if a promise is returned. You can read about async/await here.

Upvotes: 1

ElllGeeEmm
ElllGeeEmm

Reputation: 41

The problem is related to using a forEach loop for asynchronous code. This answer has more on the issue:

Using async/await with a forEach loop

Upvotes: -1

Related Questions