嵌套的异步/等待Nodejs

12

我似乎无法弄清楚为什么这对我不起作用。 我有一个父函数,在子加载过程上执行了AWAIT ... 加载过程反过来调用另一个名为LOADDATA的AWAIT ... 基本上是这样的:

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();
        });
    });
};

在LOAD中等待失败,报错信息如下:

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

显然不太理解异步的作用域!


没有理由使用 return await ...。只需返回 Promise 即可。此外,应避免将新的 Promise 包装在现有 Promise 中,以避免 Promise 反模式。 - jfriend00
1个回答

19

您只能在异步函数内使用await关键字。如果您在异步函数中嵌套了一个非异步函数,则无法在该函数中使用await

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

你在上面的.then方法中有一个回调函数,这个回调函数不是异步的。你可以通过执行async tables => {来修复这个问题。

然而,由于load是异步的且findAll返回一个Promise,因此您不需要使用.then

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

我不确定loadData具体是做什么的,也不确定是否需要按顺序加载表,但你也可以并行化操作:

我对loadData的作用并不是很确定,也不知道加载表需要按照何种顺序进行,但你可以考虑将其并行化处理:

const tables = await TableImport.findAll();
const loadPromises = tables.map(table => loadData(table.fileName, table.tableName));
await Promise.all(loadPromises);
  • return await 是多余的,因为你已经返回一个 Promise。只使用 return 即可。
  • 如果按照我建议的重写代码,你不需要使用 Promise 对象,因为你正在使用返回 Promise 的方法。
  • 你原来的函数没有解析任何内容,所以此函数通过不返回任何内容来达到相同的效果。
  • 你原始的函数还用 reject(err) 传播了一个错误。由于此函数不会在内部处理错误,因此它也会以同样的方式传播错误。

你的 loadData 函数也可以被重写并简化:

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 不需要是异步的,因为你没有使用 await。你仍然返回一个 Promise。
  • 你可能希望添加 .catch ,因为在原始代码中你没有返回错误。我上面的代码将返回由 .query 引起的错误。
  • 你传递表名并且实际上没有对返回值做任何操作,所以我完全删除了 .then

好的,我做了所有这些更改... 我理解你所有的评论,但有一个问题。以下代码无法正常工作:async function load() { return await new Promise((resolve, reject) => { const tables = await TableImport.findAll() ;当我删除 new Promise 时它可以工作... 你能解释一下为什么吗? - user3597741
还有这个语句让我有点困惑:如果您在异步函数中嵌套了一个非异步函数,则无法在该函数中使用await: 但是我将LOADDATA设置为非异步,然后可以使用await调用它--它有效... - user3597741
我认为你的意思是 function loadData { return aPromise; } ... async function load() { await loadData(); }。使用 async/await 是与作用域有关的。loadData 不在 load 函数的作用域内,它只是在该作用域中被调用。 - Explosion Pills
有点奇怪,我知道LOADDDATA返回的是Promise,但当你将其添加到Promise数组中时,它会在每一行上运行函数...而不是在调用Promise.all时运行... - user3597741
@user3597741 这是预期的行为。只是在 Promise.all 解决之前,它会等待它们全部完成。 - Explosion Pills
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接