Узел: Непонятное поведение, связанное с сохранением модели TypeORM с использованием await внутри очистки обратного вызова / обещаний - PullRequest
0 голосов
/ 24 августа 2018

Я создаю систему, которая перебирает все мои электронные письма (из папки maildir), и я использую старый пакет NPM под названием eml-format для анализа каждого файла maildir (отдельные электронные письма). Пакет eml-format не использует обещания, он просто выполняет обратный вызов после чтения файла электронной почты, и внутри этого обратного вызова я пытаюсь сохранить метаданные электронного письма в Postgres, используя await с TypeORM. Вот соответствующая часть кода, с которой у меня возникают проблемы (код выглядит немного бессмысленным, так как я удалил все, что не имеет отношения к реальной основной проблеме).

Класс Maildir () - это моя модель TypeORM (которая ссылается на таблицу postgres с именем maildir).

Этот фрагмент кода зацикливается для каждого электронного письма:

/* *****************************
 * START OF TOGGLEBLOCK
const md1 = new Maildir();
md1.folder = 'md1';
await db.entityManager.save(md1);
 * END OF TOGGLEBLOCK
***************************** */


emlformat.read(eml, { headersOnly: false }, async (error, data) => {

    console.log('before save');
    const md2 = new Maildir();
    md2.folder = 'md2';
    await db.entityManager.save(md2);
    console.log('after save');

});

При работе с кодом, как указано выше (с отключенным TOGGLEBLOCK):

  • «перед сохранением» многократно выводится на консоль
  • await db.entityManager.save(md2); не ждет, кажется, они просто встают в очередь сразу (бесполезно, когда я запускаю на своей учетной записи около 50 000 писем)
  • после того, как все они в очереди, все они сохраняются в базе данных
  • тогда все сообщения «после сохранения» выводятся на консоль одновременно

Если я просто включу код TOGGLEBLOCK, то ожидающий ответ md2 в обратном вызове будет работать точно так, как я ожидаю, для каждого письма, которое он делает это в следующем порядке:

  • показывает одно сообщение "перед сохранением"
  • сохраняет запись md2 в базе данных - ждите, как и ожидалось
  • показывает одно сообщение "после сохранения"
  • ... затем делает то же самое снова для каждого письма

Код TOGGLEBLOCK / md1 не нужен, это просто мусор, который я вставил туда, пытаясь все это выяснить. Почему наличие этого дополнительного кода вне обратного вызова меняет, работает ли в обратном вызове md2 await?

Полагаю, это как-то связано с тем, что TOGGLEBLOCK очищает обещания или что-то в этом роде?

Я просто хочу полностью удалить ненужный код TOGGLEBLOCK / md1. Как я могу заставить md2 работать без него?

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

1 Ответ

0 голосов
/ 24 августа 2018

Вы можете обернуть emlformat.read с помощью Promise, и тогда он будет хорошо играть с async/await

const readEmlFormat = eml => new Promise(
  (resolve, reject) => emlformat.read(eml, { headersOnly: false }, (error, data) => {
    if (error) {
      reject(error);
    } else {
      resolve(data);
    }

  }));

const data = await readEmlFormat(eml);
console.log('before save');
const md2 = new Maildir();
md2.folder = 'md2';
await db.entityManager.save(md2);
console.log('after save');

Обратите внимание, что проблема заключалась в том, что вы использовали асинхронную функцию в качестве обратного вызова, которого нигде не ожидали !

...