Home > Software design >  async function doesn't seem to run inside sync code
async function doesn't seem to run inside sync code

Time:02-10

im trying to make a command that connects to the database, i created a little CLI script that loops through files in specific folders to get command class modules

my problem is that in one of my commands, i'm trying to connect to sequelize, and it just doesn't seem to be doing anything. i get no output to the console, nor does it even seem to try to connect

this is probably because i'm still kind of struggling to figure out how to properly do sync / async / await stuff...notice how i use glob.sync cause i want to loop through the files sychronously, but then in my command i need to connect to the database using await

cli.js:

#! /usr/bin/env node

const patterns = [
    './node_modules/unity/src/commands/**/*.js',
    './src/commands/**/*.js',
]
const glob = require('glob')
const path = require('path')
const yargs = require('yargs')
const signature = yargs.argv._[0]
const process = require('process')

patterns.forEach(pattern => {
    glob.sync(pattern).forEach(file => {
        const commandPath = path.resolve(file)
        const command = require(commandPath)

        if (command.signature == signature) {
            command.argv = yargs.argv
            command.run()

            process.exit()
        }
    })
})

console.log('Command not found.')

here is an example command in one of the commands folders:

const { Sequelize } = require('sequelize')

class MigrateCommand {
    static signature = 'migrate'
    static argv = {}

    static run() {
        const sequelize = new Sequelize({
            dialect: 'mysql',
            host: 'localhost',
            port: 3306,
            database: 'dio_unity2',
            username: 'root',
            password: '',
        })

        const connect = async () => {
            try {
                await sequelize.authenticate()
                console.log('Connection successful.')
            }
            catch (error) {
                console.error('Unable to connect.', error)
            }
        }

        connect()

        console.log('migrate run complete')
    }
}

module.exports = MigrateCommand

i've set npx up so i can just run npx unity migrate and it will call this command based on the migrate signature

now my console should say connection successful or unable to connect and then migrate run complete, but all i see in the console is migrate run complete. it's like it isn't even trying to connect at all...

i have no idea what i'm doing wrong here.

CodePudding user response:

You can't make an asynchronous process synchronous without spawning a new thread and synchronously waiting on it. (There's an npm package that does that, via execSync.)

But the good news here is there's no need to in your code. You want to do things in series, but doing things in series isn't quite the same as doing them synchronously. Here's how:

First, run can't make the async process it's starting via authenticate synchronous. So instead, run should just be async (and we don't need connect):

static async run() {
    const sequelize = new Sequelize({
        dialect: 'mysql',
        host: 'localhost',
        port: 3306,
        database: 'dio_unity2',
        username: 'root',
        password: '',
    })

    try {
        await sequelize.authenticate()
        console.log('Connection successful.')
    } catch (error) {
        console.error('Unable to connect.', error)
    }

    console.log('migrate run complete')
}

Next, in the script, we loop through your patterns and files using an async function:

(async () => {
    for (const pattern of patterns) {
        for (const file of glob.sync(pattern)) {
            const commandPath = path.resolve(file)
            const command = require(commandPath)

            if (command.signature == signature) {
                command.argv = yargs.argv
                await command.run() // *** Note the `await`
                process.exit()
            }
        }
    }
    console.log("Command not found.")
})();

That does the work asynchronously, but one after another (in series).


If it were me, I wouldn't use process.exit() to terminate the process, it's a very aggressive form of process termination which may prevent some things from finishing (details here), and may not be as clear to people doing code maintenance later as alternatives.. Now that we've put the code in a wrapper function, I'd just return out of the function to break the loops:

await command.run();
return;
  • Related