Сценарий Node.js бездействует?

Я написал сценарий Node.js, который использует модули download , axios и fs для извлечения URL-адресов из JSON, предоставленных Федеральным регистром , и загрузки связанных файлов PDF. Тем не менее, сценарий обычно не загружает все PDF-файлы.

По какой-то причине мой скрипт «ложится» перед загрузкой всех файлов PDF. Смысл, он начинается отлично (загрузка может быть 70, 80 файлов), но затем киосков. Он не запускает мой блок catch или не сработает. Он просто перестает загружаться.

Количество файлов зависит от того, с каким Wi-Fi-соединением я подключаюсь. Тем не менее, я никогда не мог получить код для завершения и запустить блок. .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: 
", 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 здесь , если вы хотите его установить и попробовать сами. Вот краткое изложение того, что происходит, на простом английском языке:

Сценарий извлекает JSON с сервера, который содержит URL-адреса для всех 126 PDF-файлов. Затем он передает массив этих URL-адресов синхронной функции map . Каждый из URL-адресов преобразуется в обещание с модулем download . Это обещание неявно возвращено и хранится в обертке Promise.all . Когда обезвреживание обещаний будет разрешено (документ будет загружен), моя пользовательская функция writeFile будет запускаться, записывая файл PDF с загруженными данными. Когда все файлы загружены, обертка Promise.all должна быть разрешена. Но этого не происходит.

Что происходит не так?

РЕДАКТИРОВАТЬ --

Как вы можете видеть ниже, скрипт работает некоторое время, но затем он просто кивает и больше не скачивает файлы ...

введите описание изображения здесь

Всего 2 ответа


Если это действительно проблема с тарифами, есть несколько способов ее решения (в зависимости от того, как API ограничен)

Ниже приведены 3 решения в одном

rateLimited ... это увольняет запросы, ограниченные заданным количеством запросов в секунду

singleQueue ... один запрос за раз, без ограничения скорости, только все запросы в серии

multiQueue ... в большинстве 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: 
", 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"));
}

Я также немного writeFile код, так что downloadPDFS использует только обещания - весь код стиля обратного вызова узла помещается в writeFile


Как отметил Яроманда, это, скорее всего, связано с API, ограничивающим мой доступ, а не с ошибкой в ​​скрипте.

Я добавил фильтр в скрипт, чтобы выбрать меньше данных, и он работает. Следующее:

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: 
", 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)
}

Есть идеи?

10000