简体   繁体   English

异步/等待过度杀伤? 我是否不必要地使用异步并等待?

[英]Async/Await overkill? Am I unnecessarily using async and await?

I'm wondering if my small node script is pointlessly or overdoing the use of async/await. 我想知道我的小节点脚本是无意义还是过度使用async / await。 My goal was to try to find and parse as many files in parallel as possible. 我的目标是尝试尽可能并行地查找和解析尽可能多的文件。 My thoughts were it would faster. 我的想法是它会更快。

My node script that walks through a directory and any child directories and looks for .docx files. 我的节点脚本遍历目录和任何子目录并查找.docx文件。 When it finds them it runs them through Mammoth converting them into .html files. 当它找到它们时,它会通过Mammoth将它们转换为.html文件。 It just places them in a similar directory structure. 它只是将它们放在类似的目录结构中。

My code works but am I overdoing it with the async/await? 我的代码有效但是我用async / await过度了吗? Are there spots where I can eliminate their use because there is no reasoning to be using them where I am? 有没有我可以消除它们使用的地方,因为没有理由在我所在的地方使用它们?

const createTempDirs = async (catMap) => {
  try {
    const dirPromises = catMap.map((cat) => fs.mkdir(`issue/${cat.abv}`, {
      recursive: true,
    }));
    await Promise.all(dirPromises);  
  } catch (error) {
    console.log(error);
  }
};

const writeToFile = (fileName) => {
  return async (result) => {
    //return await fs.writeFile(`issue/${fileName.replace('.docx', '.html')}`);
    try {
      const [
        ,
        category,
        ...parts
      ] = fileName.split(' ');
      await createTempDirs(catMap),
      await fs.writeFile(`issue/${getShortCatName(category)}/${fileName.replace('.docx', '.html')}`, result.value);
    } catch (error) {
      console.log(error);
    }
  };
}

const fileToHTML = async (file, dirPath) => {
  try {
    const fileDetails = await fs.lstat(dirPath + file);
    if (fileDetails.isDirectory()) {
      walkDir(dirPath + addTrailingSlash(file));
    }
    if (!fileDetails.isDirectory() && path.extname(file) === '.docx') {
      mammoth.convertToHtml({
        path: dirPath + file,
      }, conversionOptions).then(writeToFile(file));
    }
  } catch (error) {
    console.log(error);
  }
};

const processFiles = async (files, dirPath) => {
  try {
    const filePromises = files.map(file => fileToHTML(file, dirPath));
    return await Promise.all(filePromises);
  } catch (error) {
    console.log(error);
  }
};

const walkDir = async (dirPath) => {
  try {
    const files = await fs.readdir(dirPath);
    processFiles(files, dirPath);
  } catch (error) {
    console.log(error);
  }
};

walkDir(dirPath);

await is generally useful when a particular block of code needs to wait for a Promise and then do something with it before finishing (possibly involving awaiting another Promise afterwards). 当一个特定的代码块需要等待一个Promise 然后在完成之前对它做一些事情 (可能涉及等待另一个 Promise之后)时, await通常很有用。 If the only await is on the last real line of the function, it makes much more sense to just return the Promise. 如果唯一的await是在函数的最后一个实线上,那么返回Promise就更有意义了。

As for try / catch , the general idea is to catch errors at the level that they can be appropriately handled . 至于try / catch ,一般的想法是在可以适当处理它们的级别捕获错误。 So, for example, if you want to stop completely when there's a problem, only catch in the outermost call, like: 因此,例如,如果您想在出现问题时完全停止, 只需 catch最外层的调用,例如:

const createTempDirs = (catMap) => Promise.all(
  catMap.map((cat) => fs.mkdir(`issue/${cat.abv}`, {
    recursive: true,
  }))
);

const writeToFile = (fileName) => {
  return async (result) => {
    //return await fs.writeFile(`issue/${fileName.replace('.docx', '.html')}`);
    const [
      ,
      category,
      ...parts
    ] = fileName.split(' ');
    await createTempDirs(catMap);
    await fs.writeFile(`issue/${getShortCatName(category)}/${fileName.replace('.docx', '.html')}`, result.value);
  };
};

const fileToHTML = async (file, dirPath) => {
  const fileDetails = await fs.lstat(dirPath + file);
  if (fileDetails.isDirectory()) {
    // see below line - remember to await or return every Promise created!
    await walkDir(dirPath + addTrailingSlash(file));
  }
  if (!fileDetails.isDirectory() && path.extname(file) === '.docx') {
    // see below line - remember to await or return every Promise created!
    return mammoth.convertToHtml({
      path: dirPath + file,
    }, conversionOptions).then(writeToFile(file));
  }
};

const processFiles = (files, dirPath) => Promise.all(files.map(file => fileToHTML(file, dirPath)));

const walkDir = async (dirPath) => {
  const files = await fs.readdir(dirPath);
  processFiles(files, dirPath);
};

Then, only catch in the entry point, the call of walkDir : 然后,只在入口点catch walkDir的调用:

walkDir(dirPath)
  .catch((err) => {
    // There was an error somewhere
  });

If you want to keep processing at a certain point when there's an error in a sub-call, then catch the error at that point, eg if a single writeFile can fail, but you don't want the error to percolate up the call chain and stop everything, try/catch in the caller of writeFile : 如果你想在子调用中出现错误时继续处理某个点,那么在那一点捕获错误,例如,如果单个writeFile可能失败,但你不希望错误渗透到调用链中并停止一切,在writeFile的调用者中try/catch

const writeToFile = (fileName) => {
  return async (result) => {
    const [
      ,
      category,
      ...parts
    ] = fileName.split(' ');
    await createTempDirs(catMap);
    try {
      await fs.writeFile(`issue/${getShortCatName(category)}/${fileName.replace('.docx', '.html')}`, result.value);
    } catch(e) {
      // writeFile failed, but the rest of the script will continue on as normal
      // the error, since it was caught here,
      // WILL NOT BE passed up to the caller of writeToFile
    }
  };
};

Make sure to await or return every single Promise you create past the entry point, so that errors will be passed up the Promise chain properly. 确保awaitreturn您在入口点之后创建的每个Promise,以便错误将正确地传递给Promise链。 (see the fixes made to fileToHTML ) (参见对fileToHTML的修复)

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

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