правильно используя асинхронные и жду - PullRequest
0 голосов
/ 22 декабря 2018

Функция ниже вызывает несколько асинхронных функций в цикле for.Он анализирует различные файлы CSV для создания одного объекта JavaScript.Я хотел бы вернуть объект после завершения цикла for.Он возвращает пустой объект сразу, пока выполняет асинхронные задачи.Имеет смысл, однако я пробовал различные комбинации Promise / async / await с надеждой запустить что-то после завершения цикла for.Я явно не понимаю, что происходит.Есть ли лучший шаблон, чтобы следовать за чем-то вроде этого, или я неправильно об этом думаю?

async function createFormConfig(files: string[]): Promise<object>

  return new Promise(resolve => {

    const retConfig: any = {};


    for (const file of files) {


      file.match(matchFilesForFormConfigMap.get('FIELD')) ?
        parseCsv(file).then(parsedData => {
          retConfig.fields = parsedData.data;
        })

        : file.match(matchFilesForFormConfigMap.get('FORM'))
        ? parseCsv(file).then(parsedData => retConfig.formProperties = parsedData.data[0])

        : file.match(matchFilesForFormConfigMap.get('PDF'))
          ? parseCsv(file).then(parsedData => retConfig.jsPdfProperties = parsedData.data[0])

          : file.match(matchFilesForFormConfigMap.get('META'))
            ? parseCsv(file).then(parsedData => {
              retConfig.name = parsedData.data[0].name;
              retConfig.imgType = parsedData.data[0].imgType;
              // console.log(retConfig);  <- THIS CONSOLE WILL OUTPUT RETCONFIG LOOKING LIKE I WANT IT
            })

            : file.match(matchFilesForFormConfigMap.get('PAGES'))
              ? parseCsv(file).then(parsedData => retConfig.pages = parsedData.data)
              : console.log('there is an extra file: ' + file);

    }

    resolve(retConfig);  // <- THIS RETURNS: {}
  });

Это код, который я использую для вызова функции в надежде заполнить мой 'retConfig'данные CSV.

getFilesFromDirectory(`${clOptions.directory}/**/*.csv`)
  .then(async (files) => {
    const config = await createFormConfig(files);
    console.log(config);
  })
  .catch(err => console.error(err));

};

Ответы [ 2 ]

0 голосов
/ 22 декабря 2018

Во-первых, функция async возвращает Promise, поэтому вам не нужно возвращать одно явное. Вот как вы можете упростить ваш код:

async function createFormConfig(files: string[]): Promise<object> {

  // return new Promise(resolve => { <-- remove

  const retConfig: any = {};

  // ...

  // The value returned by an async function is the one you get
  // in the callback passed to the function `.then` 
  return retConfig;

  // }); <-- remove
}

Затем ваша функция createFormConfigвозвращает конфигурацию до того, как она закончила вычислять.Вот как вы можете вычислить его перед возвратом:

async function createFormConfig(files: string[]): Promise<object> {

  const retConfig: any = {};

  // Return a Promise for each file that have to be parsed
  const parsingCsv = files.map(async file => {
    if (file.match(matchFilesForFormConfigMap.get('FIELD'))) {
      const { data } = await parseCsv(file);
      retConfig.fields = data;
    } else if (file.match(matchFilesForFormConfigMap.get('FORM'))) {
      const { data } = await parseCsv(file);
      retConfig.formProperties = data[0];
    } else if (file.match(matchFilesForFormConfigMap.get('PDF'))) {
      const { data } = await parseCsv(file);
      retConfig.jsPdfProperties = data[0];
    } else if (file.match(matchFilesForFormConfigMap.get('META'))) {
      const { data } = await parseCsv(file);
      retConfig.name = data[0].name;
      retConfig.imgType = data[0].imgType;
    } else if (file.match(matchFilesForFormConfigMap.get('PAGES'))) {
      const { data } = await parseCsv(file);
      retConfig.pages = data;
    } else {
      console.log('there is an extra file: ' + file);
    }
  });

  // Wait for the Promises to resolve
  await Promise.all(parsingCsv)

  return retConfig;
}
0 голосов
/ 22 декабря 2018

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

Кроме того, вы сделали асинхронную функцию, но фактически нигде не используете await.Таким образом, цикл for проходит весь цикл до разрешения любого из ваших обещаний.Вот почему ни одна из данных не попадает в ваш объект.

Это действительно упростит ваш код, чтобы использовать только await и избавиться от вызовов then().Например, вы можете сделать это:

async function createFormConfig(files: string[]): Promise<object> {

  const retConfig: any = {};

  for (const file of files) {

    if (file.match(matchFilesForFormConfigMap.get('FIELD')){
      // no need for the then here
      let parsedData = await parseCsv(file)
      retConfig.field = parsedData.data
    }

   // ...etc

В конце вы можете просто вернуть значение:

return retConfig
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...