Данные из одного асинхронного выполнения функции смешиваются с другим выполнением функции
Я писал API веб-скрепинга, построенный на основе NodeJS, используя Cheerio, node-fetch и fs-extra. В следующем фрагменте кода я вызываю метод getReport для каждой строки в массиве config.supportedMountains. Для каждого из элементов я хочу запустить их через функцию fetchAndStore, которая делает запрос html, запускает его через определенный анализатор и затем сохраняет результаты json.
// const fs = require('fs-extra');
const _ = require('lodash');
// const Promise = require('promise');
const schedule = require('node-schedule');
const fetchAndStore = require('./fetchAndStore.js');
const config = require('../config.js');
exports.run = function() {
schedule.scheduleJob('*/20 * * * * *', function() {
// Get the most recent reports
// And write them to storage
_.forEach(config.supportedMountains, function(fName) {
getReport(fName);
});
});
};
/**
* Gets the lift statuses for every mountain
* @param {string} fName the file name of the mountain
* @return {promise} the promise resolved when the file is written
*/
function getReport(fName) {
return fetchAndStore.run(fName);
}
Здесь вы можете увидеть файл загрузки и сохранения. Этот файл принимает имя fName и требует соответствующий файл staticData. Этот файл содержит URL для загрузки страницы. Теперь выполняется html-запрос, и он запускается через анализатор. Затем с полученным проанализированным json проходит несколько шагов для его сохранения. Окончательный вывод должен состоять из двух файлов, один из которых хранит отчеты, а другой - исторический снегопад, большая часть логики в функциях fs.outputJson заключается в обработке отсутствующих файлов.
const fs = require('fs-extra');
const fetch = require('node-fetch');
exports.run = (function(fName) {
// Get the staticJson
let staticJson = require(`../staticData/mountains/${fName}.json`);
// console.log(staticJson.id)
// Output the report
return fetch(staticJson.urls.reportFetchUrl).then(function(res) {
return res.text();
}).then(function(html) {
// Run the html through the parser
let parser = require(`../scrapers/${staticJson.sName}.js`);
parsed = parser.run(html);
// Output the report
return fs.outputJson(
`data/reports/${staticJson.id}.json`,
parsed.report
).then(function() {
// console.log(parsed.report.lifts[0].name);
// Once output is completed
if (parsed.snowHistory) {
// If snow history is defined
// Read the old file
return fs.readJson(
`data/snowHistory/${staticJson.id}.json`
).then(function(oldJson) {
// If the date of the old json is todays date
if (oldJson[0].date === parsed.snowHistory.date) {
// Replace the first element in array
oldJson[0] = parsed.snowHistory;
return fs.outputJson(
`data/snowHistory/${staticJson.id}.json`,
oldJson
);
} else {
// If this is a fresh entry
oldJson.unshift(parsed.snowHistory);
// If the record does not exist
return fs.outputJson(
`data/snowHistory/${staticJson.id}.json`,
oldJson
);
}
}).catch(function(e) {
// If the old file cannot be read
if (e.code === 'ENOENT') {
// If the file does not exist
// Write brand new file
return fs.outputJson(
`data/snowHistory/${staticJson.id}.json`,
[parsed.snowHistory]
);
}
});
}
});
});
});
По какой-то причине, когда работает скребок, примерно в 1/4 времени данные из одного выполнения fetchAndStore будут смешиваться с данными из другого выполнения fetchAndStore, что означает, что в файловую систему будут записаны неправильные данные. Как это возможно? Я подумал, что, поскольку я делаю вызовы fetchAndStore.run() отдельно, данные не могут быть перепутаны. Есть идеи, почему это происходит?
1 ответ
Первое, что я вижу, это то, что parsed
глобально ограничен. Может ли это быть проблемой? Кроме того, если вы вкладываете это глубоко, вы действительно должны рассмотреть возможность разбить это на несколько функций.