web-dev-qa-db-ja.com

ネストされた非同期/待機Nodejs

なぜこれがうまくいかないのか理解できないようです。子ロードプロセスでAWAITを実行する親関数があります... LOADプロセスは、次に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は次のように失敗します。

aload loadData(table.fileName、table.tableName); SyntaxError:予期しない識別子

明らかに非同期のスコープについて何かを理解していない!

6
user3597741

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が何をしているか、またテーブルを順番にロードする必要があるかどうかは正確にはわかりませんが、これを並列化することもできます。

_const tables = await TableImport.findAll();
const loadPromises = tables.map(table => loadData(table.fileName, table.tableName));
await Promise.all(loadPromises);
_
  • _return await_は、すでにpromiseを返しているので不要です。 returnだけで動作します。
  • 私が提案したように書き換える場合は、とにかくプロミスを返すメソッドを使用しているため、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は非同期である必要はありません。あなたはまだ約束を返しています。
  • 元のコードではエラーが返されなかったため、_.catch_を追加することができます。上記の私のコードは、_.query_が原因のエラーを返します。
  • テーブル名を渡し、実際には戻り値で何もしないので、_.then_を完全に削除しました。
12
Explosion Pills