Использование try finally для await — хороший вариант?

#javascript #node.js

#javascript #node.js

Вопрос:

Мне нужно выполнить цикл и дождаться измененного результата в конце await вызова функции.

Что было бы лучшим вариантом дождаться всего выполнения и только после завершения цикла вернуть результат?

 try {
    for await (var [i, object] of tablesArchive.data.entries()) {
        if (Object.keys(object).length === 0) {
            continue;
        }

        // Busca IDs de relacoes existentes
        await this.getIdByRalations(tablesArchive, object, async (newObject) => {
            where = { [whereByProperty]: newObject[whereByProperty] };
            // Atualiza ou cria o registro na base de dados
            const registro = await this.upsertWithWhere(app, tablesArchive.modelName, where, newObject);
            tablesArchive.data[i].id = registro.id;
        });
    }
 } finally {
    console.log('FINALLY ');
    return tablesArchive.data;
 }
  

В приведенном выше случае мне нужно изменить tablesArchive.data объект и только после просмотра всех индексов и обновления информации. Я хочу вызвать return со всеми изменениями.

Комментарии:

1. Какое отношение к этому имеет try / finally?

2. Вы можете пропустить try / finally и просто запустить цикл for, за которым следует код, который вы хотите запустить после цикла for .

Ответ №1:

Вы не нуждаетесь в этом строго. Ваше использование await уже заставляет код «ждать», пока он не будет завершен, чтобы выполнить последние 2 оператора.

Конкретный пример того, зачем вам может понадобиться finally, заключается в том, что в вашем try блоке может возникнуть исключение, и вы хотите убедиться, что код в блоке finally всегда выполняется, исключение или нет.

Я не думаю, что это то, что вам нужно добавлять по умолчанию всякий раз, когда возникает вероятность возникновения исключения. Вопрос в том, что вы хотите сделать в случае исключения? Я думаю, что способ по умолчанию справиться с этим — позволить исключению генерировать и откатывать стек, и его поймает только первое, что может с ним что-то сделать.

Есть конкретный случай, когда мне всегда нужен блок finally, когда я делаю что-то, связанное с базой данных, в соединении, и мне нужно освободить соединение, независимо от того, было вызвано исключение или нет:

 try {
  const conn = pool.getConnection();
  await conn.query('...');
  await conn.query('...');
} finally {
   // Always release, error or not
   conn.release();
}
  

Приведенный выше блок кода достаточно распространен в моем исходном коде, но это только потому, что есть конкретная вещь, которую я хочу выполнить, независимо от того, происходит исключение или нет.

Комментарии:

1. Проблема в том, что я вызываю асинхронную функцию внутри for. Без finally try для выполнения узел не ожидает возврата … Только использование try окончательно решило мою проблему. Но мне нужны были другие мнения и способы решения проблемы.

2. @PedroFelipeEliasDeSouza похоже getIdByRalations() , что это функция в стиле обратного вызова. Можете ли вы преобразовать его в функцию, основанную на обещаниях? Это был бы мой подход. finally здесь это не будет иметь значения.

Ответ №2:

Вы можете поместить try / catch внутри цикла for и в блок catch, просто зарегистрируйте ошибку. Затем он продолжит выполнение, и вы можете поместить свой оператор return сразу после цикла for .

 for (var [i, object] of tablesArchive.data.entries()) {
  try {
    if (Object.keys(object).length === 0) {
      continue;
    }

    // Busca IDs de relacoes existentes
    await this.getIdByRalations(tablesArchive, object, async (newObject) => {
        where = { [whereByProperty]: newObject[whereByProperty] };
        // Atualiza ou cria o registro na base de dados
        const registro = await this.upsertWithWhere(app, tablesArchive.modelName, where, newObject);
        tablesArchive.data[i].id = registro.id;
    });
  } catch (e) {
    console.log(e);
  }
}
return tablesArchive.data;
  

Ответ №3:

Здесь взгляните на API Promise.all() .

Краткое резюме: вы предоставляете массив обещаний Promise.all() и ждете, пока все обещания в этом массиве не будут завершены.

В вашем примере я бы сделал это так:

 var promises = []
for await (var [i, object] of tablesArchive.data.entries()) {
    if (Object.keys(object).length === 0) {
        continue;
    }

    // I changed this line here
    // just push every async function to the promises array
    promises.push(this.getIdByRalations(tablesArchive, object, async (newObject) => {
        where = { [whereByProperty]: newObject[whereByProperty] };
        // Atualiza ou cria o registro na base de dados
        const registro = await this.upsertWithWhere(app, tablesArchive.modelName, where, newObject);
        tablesArchive.data[i].id = registro.id;
    }));
}

return await Promise.all(promises).then(() => {
    console.log('All promises are finished')
    return tablesArchive.data
}).catch(err => {
    console.error('Error occured in Promises.all: '   err)
}).finally(() => {
    console.log('All promises Finished')
})