重构复杂的嵌套Node.js函数

时间:2018-09-28 23:47:21

标签: javascript node.js asynchronous promise refactoring

我在下面有以下代码段。目前可以使用,但是我希望对其进行一些优化/重构。

基本上,它会获取JSON数据,从响应中提取多个PDF的网址,然后将这些PDF下载到一个文件夹中。

我希望重构此代码,以便在PDF全部下载后对其进行处理。目前,我不确定该怎么做。有很多嵌套的异步函数。

我该如何重构它以允许我在错误处理程序之前处理另一个.then调用,以便随后可以处理已下载的PDF?

const axios = require("axios");
const moment = require("moment");
const fs = require("fs");
const download = require("download");
const mkdirp = require("mkdirp"); //  Makes nested files...
const getDirName = require("path").dirname; // Current directory name...

const today = moment().format("YYYY-MM-DD");

function writeFile(path, contents, cb){
  mkdirp(getDirName(path), function(err){
    if (err) return cb(err)
      fs.writeFile(path, contents, cb)
  })
};

axios.get(`http://federalregister.gov/api/v1/public-inspection-documents.json?conditions%5Bavailable_on%5D=${today}`)
  .then((res) => {
    res.data.results.forEach((item) => {
      download(item.pdf_url).then((data) => {
        writeFile(`${__dirname}/${today}/${item.pdf_file_name}`, data, (err) => {
          if(err){
            console.log(err);
          } else {
            console.log("FILE WRITTEN: ", item.pdf_file_name);
          }
        })
      })
    })
  })
  .catch((err) => {
    console.log("COULD NOT DOWNLOAD FILES: \n", err);
  })

感谢大家提供的任何帮助。

P.S。 -当我现在只需接通.then呼叫时,它将立即触发。这意味着我的forEach循环是非阻塞的吗?我以为forEach循环正在阻塞。

1 个答案:

答案 0 :(得分:2)

当前的forEach同步运行,并且不会等待异步操作完成。您应该使用.map而不是forEach,以便可以将每个项目从Promise映射到其download。然后,您可以在结果数组上使用Promise.all,一旦完成所有download的解析,即可解析:

axios.get(`http://federalregister.gov/api/v1/public-inspection-documents.json?conditions%5Bavailable_on%5D=${today}`)
  .then(processResults)
  .catch((err) => {
    console.log("COULD NOT DOWNLOAD FILES: \n", err);
  });
function processResults(res) {
  const downloadPromises = res.data.results.map((item) => (
    download(item.pdf_url).then(data => new Promise((resolve, reject) => {
      writeFile(`${__dirname}/${today}/${item.pdf_file_name}`, data, (err) => {
        if(err) reject(err);
        else resolve(console.log("FILE WRITTEN: ", item.pdf_file_name));
      });
    }))
  ));
  return Promise.all(downloadPromises)
    .then(() => {
      console.log('all done');
    });
}

如果您想在每次迭代中实质上阻塞该函数,则可以将async函数与await结合使用。