繁体   English   中英

正确使用异步并等待

[英]properly using async and await

下面的函数在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));

};

首先,一个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;
}

异步函数已经返回了Promise,您无需将代码包装在新的代码中。 只需从函数中返回一个值,调用者将收到一个承诺,该承诺将解析为返回的值。

另外,您已经实现了异步功能,但实际上并没有await任何地方使用await 因此,for循环会在您的任何promise解决之前贯穿整个循环。 这就是为什么没有数据将其放入您的对象的原因。

它实际上将简化您的代码,使其仅使用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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM