代码之家  ›  专栏  ›  技术社区  ›  Harrison Cramer

Node.js脚本静默失败?

  •  0
  • Harrison Cramer  · 技术社区  · 6 年前

    download , axios fs Federal Register ,并下载相关的PDF文件。但是,脚本通常无法下载所有PDF。

    不管出于什么原因,我的脚本在下载所有PDF文件之前都会“暂停”。也就是说,它一开始很好(下载了70、80个文件),但后来就停滞不前了。它不会触发我的捕获块,或者以任何方式失败。它只是停止下载。

    文件的数量根据我使用的wifi连接而有所不同。但是,我一直无法完成代码并启动 .then 阻止我的代码。理想情况下,我想使用.then块来处理下载后的文件。

    代码如下:

    // The callback function that writes the file...
    function writeFile(path, contents, cb){
      mkdirp(getDirName(path), function(err){
        if (err) return cb(err)
          fs.writeFile(path, contents, cb)
      })
    };
    
    // The function that gets the JSON...
    axios.get(`http://federalregister.gov/api/v1/public-inspection-documents.json?conditions%5Bavailable_on%5D=${today}`)
      .then(downloadPDFS)
      .catch((err) => {
        console.log("COULD NOT DOWNLOAD FILES: \n", err);
      });
    
    // The function that downloads the data and triggers my write callback...
    function downloadPDFS(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((res) => console.log("DONE"))
    }
    

    here ,以防您想安装它并自己尝试。下面用通俗易懂的英语总结一下情况:

    该脚本从服务器获取JSON,其中包含所有126个pdf的url。然后它将这些url的数组传递给同步 map 功能。每个url都被转换成一个promise,其中 下载 模块。这个承诺被隐式地返回,并存储在 Promise.all 包装器。当下载承诺解决(文档下载完成)我的自定义writeFile函数将触发,用下载的数据写入PDF文件。下载完所有文件后 包装器应解析。但那不会发生。

    出什么问题了?

    编辑--

    正如你在下面看到的,这个脚本运行了一段时间,但是它只是暂停,不再下载任何文件。。。

    enter image description here

    2 回复  |  直到 6 年前
        1
  •  1
  •   Jaromanda X    6 年前

    如果这真的是一个速率问题,那么有几种方法可以解决它(取决于API如何限制速率)

    下面有三种解决方案

    rateLimited ... 这将触发限制为每秒给定请求数的请求

    singleQueue ... 一次一个请求,没有速率限制,只是一系列的请求

    multiQueue ... 一次最多只能有给定数量的请求“在飞行中”

    const rateLimited = perSecond => {
        perSecond = isNaN(perSecond) || perSecond < 0.0001 ? 0.0001 : perSecond;
        const milliSeconds = Math.floor(1000 / perSecond);
        let promise = Promise.resolve(Date.now);
        const add = fn => promise.then(lastRun => {
            const wait = Math.max(0, milliSeconds + lastRun - Date.now);
            promise = promise.thenWait(wait).then(() => Date.now);
            return promise.then(fn);
        });
        return add;
    };
    const singleQueue = () => {
        let q = Promise.resolve();
        return fn => q = q.then(fn);
    };
    const multiQueue = length => {
        length = isNaN(length) || length < 1 ? 1 : length;
        const q = Array.from({ length }, () => Promise.resolve());
        let index = 0;
        const add = fn => {
            index = (index + 1) % length;
            return q[index] = q[index].then(fn);
        };
        return add;
    };
    
    // uncomment one, and only one, of the three "fixup" lines below
    let fixup = rateLimited(10); // 10 per second for example
    //let fixup = singleQueue;   // one at a time
    //let fixup = multiQueue(6); // at most 6 at a time for example
    
    const writeFile = (path, contents) => new Promise((resolve, reject) => {
        mkdirp(getDirName(path), err => {
            if (err) return reject(err);
            fs.writeFile(path, contents, err => {
                if (err) return reject(err);
                resolve();
            })
        })
    });
    
    
    axios.get(`http://federalregister.gov/api/v1/public-inspection-documents.json?conditions%5Bavailable_on%5D=${today}`)
        .then(downloadPDFS)
        .catch((err) => {
            console.log("COULD NOT DOWNLOAD FILES: \n", err);
        });
    
    function downloadPDFS(res) {
        const downloadPromises = res.data.results.map(item => fixup(() => 
            download(item.pdf_url)
            .then(data => writeFile(`${__dirname}/${today}/${item.pdf_file_name}`, data))
            .then(() => console.log("FILE WRITTEN: ", item.pdf_file_name))
        ));
        return Promise.all(downloadPromises).then(() => console.log("DONE"));
    }
    

    我也对代码进行了一些重构 downloadPDFS 只使用承诺-所有节点回调样式的代码都放入 writeFile

        2
  •  0
  •   Harrison Cramer    6 年前

    我在脚本中添加了一个过滤器,以选择较少的数据,它可以正常工作。具体如下:

    axios.get(`http://federalregister.gov/api/v1/public-inspection-documents.json?conditions%5Bavailable_on%5D=${today}`)
      .then(downloadPDFS)
      .then(() => {
        console.log("DONE")
      })
      .catch((err) => {
        console.log("COULD NOT DOWNLOAD FILES: \n", err);
      });
    
    function downloadPDFS(res) {
      const EPA = res.data.results.filter((item) => {
        return item.agencies[0].raw_name === "ENVIRONMENTAL PROTECTION AGENCY"; //// THIS FILTER
      });
    
      const downloadPromises = EPA.map(item => ( //// ONLY DOWNLOADING SOME OF THE DATA
        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)
    }
    
    推荐文章