javascript - Node.js 脚本默默失败?

标签 javascript node.js asynchronous callback promise

我编写了一个 Node.js 脚本,该脚本使用 downloadaxiosfs 模块从由Federal Register ,并下载相关的 PDF 文件。但是,该脚本通常无法下载所有 PDF。

无论出于何种原因,我的脚本在下载所有 PDF 文件之前都会“停止”。意思是,它一开始很好(可能下载 70、80 个文件),但随后就停止了。它不会触发我的 catch block ,也不会以任何方式失败。它只是停止下载。

文件数量根据我使用的 WiFi 连接而有所不同。但是,我始终无法完成代码并触发代码中的 .then block 。理想情况下,我想在下载文件后使用 .then block 来处理文件。

这是代码:

// 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"))
}

我的项目在Github here ,如果您想安装它并亲自尝试。以下是用简单的英语总结的情况:

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

出了什么问题?

编辑--

正如您在下面看到的,脚本运行了一段时间,但随后它就停止了并且不再下载任何文件...

enter image description here

最佳答案

如果确实是速率问题,那么有几种方法可以解决它(取决于 API 的速率限制方式)

下面有 3 个解决方案合二为一

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 仅使用 Promise - 所有 Node 回调样式代码都放入 writeFile

关于javascript - Node.js 脚本默默失败?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52564601/

相关文章:

javascript - 来自 C++ 线程的节点 FFI 回调

javascript - 通过单击访问对象函数

java webapp 中的 javascript 预处理器

ios - 延迟的 OCMock 验证/处理单元测试中的超时

c# - 在使用 async/await 进行请求时为多个函数调用返回相同的值

c++ - 使用 libdrizzle 作为异步 mysql 连接器

javascript - php 类型转换出错?

javascript - 图像可以包含在网页中但不能复制/保存吗?

node.js - Sequelize 包含返回数据格式

javascript - 最快的手指优先应用程序架构 - Redis?