数据从一个函数的asynchronous执行与另一个函数的执行混合在一起

我一直在使用Cheerio,node-fetch和fs-extra编写一个基于NodeJS构build的Web抓取API。 在下面的一段代码中,我调用getReport方法,为config.supportedMountains数组中的每个string。 对于每一个项目,我想通过fetchAndStore函数运行它们,这使得html请求,通过特定的parsing器运行它,然后存储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请求已经完成,并且通过parsing器运行。 然后,通过parsing出的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] ); } }); } }); }); }); 

由于某种原因,当scraper运行时,大约有1/4的时间,fetchAndStore的一次执行的数据会与另一次执行fetchAndStore的数据混合在一起,这意味着错误的数据将被写入文件系统。 这怎么可能? 我想,因为我正在分别调用fetchAndStore.run(),所以数据将无法混合起来。 任何想法为什么发生这种情况?

我看到的第一件事是parsed是全局范围的。 这可能是问题吗? 顺便说一下,如果你深入地嵌套,你应该考虑在一些function上打破这个问题。