Steam gamer
Steam gamer

Reputation: 217

Functions are not waiting until they are resolved

I'm trying to execute functions one at a time, sequentially. Using promises, I believe it should work, but for me, it does not work. I've researched somewhat and found this question, and one of the answers explains to use Promises, that is what I've been trying to do.

Here's the functions:

async function loadCommands () {
  return new Promise((resolve, reject) => {
    let commands = 0;
    readdir('./commands/', (error, files) => {
      if (error) reject(error);
      for (const file of files) {
        if (!file.endsWith('.js')) return;
        commands++;
      }
    }
    resolve(commands); // this is in my code, I forgot to put it - sorry commenters
  });
};

async function loadEvents () {
  return new Promise(async (resolve, reject) => {
    let events = 0;
    readdir('./events/', (error, files) => {
      if (error) reject (error);
      for (const file of files) {
        if (!file.endsWith('.js')) return;
        events++
      }
    });
    resolve(events);
  });
};

I am then using await in an async function to try and make sure it each function resolves before going onto the next function:

console.log('started');
const events = await loadEvents();
console.log(events);
console.log('load commands');
const commands = await loadCommands();
console.log(commands);
console.log('end')

In the console, this is linked (keep in mind, I have no files in ./events/ and I have one file in ./commands/):

start
0 // expected
load commands
0 // not expected, it's supposed to be 1
end

What am I doing wrong? I want these functions to be run sequentially. I've tried making it so instead of functions, it's just the bare code in the one async function, but still came to the issue.

Upvotes: 0

Views: 94

Answers (2)

Hemant Parashar
Hemant Parashar

Reputation: 3774

You're trying to use await outside async. You can await a promise only inside an async function. The functions returning promises ( here loadCommands & loadEvents ) don't need to be async. Make an async wrapper function like run and call the await statements inside it like this.

PS: Plus you also need to resolve loadCommands with commands in the callback itself. Same for loadEvents. Also, remove the return and simple increment the variable when true.

 function loadCommands() {
   return new Promise((resolve, reject) => {
       let commands = 0;
       readdir('./commands/', (error, files) => {
           if (error) reject(error);
           for (const file of files) {
             if (file.endsWith('.js')) commands++;
           }
         }
       resolve(commands);
       });
   };

   function loadEvents() {
     return new Promise((resolve, reject) => {
       let events = 0;
       readdir('./events/', (error, files) => {
         if (error) reject(error);
         for (const file of files) {
           if (file.endsWith('.js')) events++
         }
         resolve(events);
       });

     });
   };

   async function run() {
     console.log('started');
     const events = await loadEvents();
     console.log(events);
     console.log('load commands');
     const commands = await loadCommands();
     console.log(commands);
     console.log('end')
   }

   run();

Hope this helps !

Upvotes: 0

Bergi
Bergi

Reputation: 665344

You never resolve() the promise that you create in loadCommands, and you resolve() the promise that you create in loadEvents before the readdir callback happened.

Also, don't do any logic in non-promise callbacks. Use the new Promise constructor only to promisify, and call only resolve/reject in the async callback:

function readdirPromise(path) {
    return new Promise((resolve, reject) => {
        readdir(path, (err, files) => {
            if (err) reject(err);
            else resolve(files);
        });
    });
});

or simply

import { promisify } from 'util';
const readdirPromise = promisify(readdir);

Then you can use that promise in your actual logic function:

async function countJsFiles(path) {
    const files = await readdirPromise(path);
    let count = 0;
    for (const file of files) {
        if (file.endsWith('.js'))
            count++;
        // I don't think you really wanted to `return` otherwise
    }
    return count;
}
function loadCommands() {
    return countJsFiles('./commands/');
}
function loadEvents() {
    return countJsFiles('./events/');
}

Upvotes: 1

Related Questions