Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nested Async/Await Nodejs

Cannot seem to figure out why this is not working for me. I have a parent function that performs an AWAIT on a child load process... the LOAD process in turn calls another AWAIT called LOADDATA... so basically like this:

module.exports = async function () {
    try {
       await load();

    } catch (ex) {
        console.log(ex);
        logger.error(ex);
    }
};

async function load() {
    return await new Promise((resolve, reject) => {
        TableImport.findAll().then((tables) => {
           for (let table of tables) {
                await loadData(table.fileName, table.tableName);
            }
            resolve();
        }).catch(function (err) {
            reject(err);
        })
    })
};


async function loadData(location, tableName) {
    return await new Promise(function (resolve, reject) {
        var currentFile = path.resolve(__dirname + '/../fdb/' + location);

        sequelize.query("LOAD DATA LOCAL INFILE '" + currentFile.replace('/', '//').replace(/\\/g, '\\\\') + "' INTO TABLE " + tableName + " FIELDS TERMINATED BY '|'").then(function () {
            resolve(tableName);
        }).catch(function (ex) {
            reject();
        });
    });
};

the AWAIT in the LOAD fails stating:

await loadData(table.fileName, table.tableName); SyntaxError: Unexpected identifier

Clearly do not understand something about scope of the async!

like image 838
user3597741 Avatar asked Dec 21 '17 16:12

user3597741


1 Answers

You can only use await inside of an async function. If you have a non-async function nested inside of an async function, you can't use await in that function:

async function load() {
    return await new Promise((resolve, reject) => {
        TableImport.findAll().then((tables) => {
           for (let table of tables) {
               await loadData(table.fileName, table.tableName);

You have a callback to the .then method above. This callback is not async. You could fix this by doing async tables => {.

However since load is async and findAll returns a promise, you don't need to use .then:

async function load() {
    const tables = await TableImport.findAll();
    for (let table of tables) {
        await loadData(table.fileName, table.tableName);
    }
}

I'm not exactly sure what loadData does and if you have to load the tables in order, but you can also parallelize this:

const tables = await TableImport.findAll();
const loadPromises = tables.map(table => loadData(table.fileName, table.tableName));
await Promise.all(loadPromises);
  • The return await is superfluous since you are already returning a promise. Just return will work.
  • If you rewrite as I suggested, you don't need to use a Promise object since the methods you are working with return promises anyway.
  • Your original function was resolving nothing, so this function works the same by returning nothing.
  • Your original function was also propagating an error with reject(err). This function does not handle an error internally so it will also propagate the error in the same way.

Your loadData function can also be rewritten and simplified quite a bit:

function loadData(location, tableName) {
    const currentFile = path.resolve(__dirname + '/../fdb/' + location);
    return sequelize.query("LOAD DATA LOCAL INFILE '" + currentFile.replace('/', '//').replace(/\\/g, '\\\\') + "' INTO TABLE " + tableName + " FIELDS TERMINATED BY '|'");
};
  • loadData doesn't need to be async since you don't use await. You are still returning a promise.
  • You may want to add .catch since in your original code you didn't return an error. My code above will return the error caused by .query.
  • You pass the table name in and you don't actually do anything with the return value, so I just removed the .then entirely.
like image 194
Explosion Pills Avatar answered Oct 19 '22 23:10

Explosion Pills