Problem
I have 3 functions which are dependent of one another and therefore I would want them to run sequentially. The function called are async and return promise and it takes time to run.
My Code - Index.js
#Function One
scrapA.scrap().then(data => {
readWriteToFile.writeToFile(data, 'scrapA-data-' timestamp, 'json');
});
#Function Two
compare.compareData('./output/json/data.json', './output/json/scraped-data-' timestamp '.json').then(data => {
let dataWithStockData = data;
let mapDatas = dataWithStockData.map( obj => {
let finalObj = {
manufacturer: obj.manufacturer,
grade: obj.condition,
carrier: obj.carrier,
stock: obj.stock,
}
return finalObj;
});
#Function Three
readWriteToFile.writeToFile(data, 'data-with-stock-' timestamp, 'csv'); });
My Code - compare.js
async function compareData(models, competitorsData) {
try {
const modelsArr = JSON.parse(fs.readFileSync(models, { encoding: 'utf8', flag: 'r' }));
const competitorsDataArr = JSON.parse(fs.readFileSync(competitorsData, { encoding: 'utf8', flag: 'r' }));
//Loop through both array of json data
modelsArr.forEach((device, deviceKey) => {
competitorsDataArr.forEach((scrapedData, scrapedDataKey) => {
if (
scrapedData.manufacturer.toLowerCase() === data.manufacturer.toLowerCase()
) {
modelsArr[dataKey]['stk'] = scrapedData.stk;
}
})
});
return modelsArr;
} catch (error) {
console.log("Error", error);
throw error;
}
}
My Code - readWriteToFile.js
async function writeToFile(data, filename, type) {
let finalData = '';
if (type == "json") {
finalData = JSON.stringify(data);
} else if (type == "csv") {
finalData = arrayToCSV(data);
} else {
console.log("File type not supported");
process.exit(1);
}
fs.writeFile("./output/" type '/' filename '.' type, finalData, (err) => {
if (err) {
console.log(err);
} else {
console.log("File written successfully\n");
}
});
}
My solution
I simply wrapped all my function calls in async and added await at the front. I does not work and it does not throw any errors.
(async () => {
await scraperA.scrap().then(data => {
console.log("DATA", data);
readWriteToFile.writeToFile(data, 'scraped-data-' timestamp, 'json');
});
await compare.compareData('./output/json/data.json', './output/json/scraped-data-' timestamp '.json').then(data => {
let dataWithStockData = data;
mapData = dataWithStock.map( obj => {
let finalObj = {
manufacturer: obj.manufacturer,
grade: obj.condition,
stock: obj.stock,
}
return finalObj;
});
});
await readWriteToFile.writeToFile(mapData, 'data-with-stock-' timestamp, 'csv');
});
CodePudding user response:
It's difficult to answer without knowing which of the functions you are calling are synchronous or not. But making the following assumptions:
- readWriteToFile.writeToFile returns a Promise (or it is async)
- mapData is defined elsewhere
You must:
- Add a return statement to the last line of the first
.then(...)
block - As jabaa said, you have to actually invoke the function.
(async () => {
await scraperA.scrap().then(data => {
console.log("DATA", data);
return readWriteToFile.writeToFile(data, 'scraped-data-' timestamp, 'json');
});
await compare.compareData('./output/json/data.json', './output/json/scraped-data-' timestamp '.json').then(data => {
let dataWithStockData = data;
mapData = dataWithStock.map( obj => {
let finalObj = {
manufacturer: obj.manufacturer,
grade: obj.condition,
stock: obj.stock,
}
return finalObj;
});
});
await readWriteToFile.writeToFile(mapData, 'data-with-stock-' timestamp, 'csv');
})();
CodePudding user response:
The code structure
(async () => {
/* your code */
});
suggests you want to create an async Immediately Invoked Function Expression (IIFE). But you have to invoke it (()
at the end):
(async () => {
/* your code */
})();
Using current versions of Node.js you don't need an async IIFE. Node.js supports top-level await.
Since readWriteToFile.writeToFile
and compare.compareData
don't return a promise, you can't call .then
and await
doesn't make sense.
Starting with Node.js v14.8, you can write
await scraperA.scrap().then(data => {
console.log("DATA", data);
readWriteToFile.writeToFile(data, 'scraped-data-' timestamp, 'json');
});
const dataWithStockData = compare.compareData('./output/json/data.json', './output/json/scraped-data-' timestamp '.json')
mapData = dataWithStock.map( obj => {
let finalObj = {
manufacturer: obj.manufacturer,
grade: obj.condition,
stock: obj.stock,
}
return finalObj;
});
readWriteToFile.writeToFile(mapData, 'data-with-stock-' timestamp, 'csv');
After you fixed the problem, you could consider using either .then
or await
/ async
to clean up your code. Mixing them is usually considered bad code style.
const data = await scraperA.scrap();
console.log("DATA", data);
readWriteToFile.writeToFile(data, 'scraped-data-' timestamp, 'json');
const dataWithStockData = compare.compareData('./output/json/data.json', './output/json/scraped-data-' timestamp '.json');
mapData = dataWithStock.map( obj => {
let finalObj = {
manufacturer: obj.manufacturer,
grade: obj.condition,
stock: obj.stock,
}
return finalObj;
});
readWriteToFile.writeToFile(mapData, 'data-with-stock-' timestamp, 'csv');
CodePudding user response:
You seem to misunderstand the async/await.
The async/await replaces the .then, so for example: lets say you have 2 funcions func1 and func2
const func1 = async () => {
//do something in the background
}
const func2 = async () => {
// do something in the background
}
The way to call these functions so they are executed sequentially is simply
const wrapperFunc = async () => {
await func1();
await func2();
}
So in your case, you could do this
#Function One
const wrapperFunc = async () => {
const data1 = await scrapA.scrap()
// IF writeToFile is a Promise
await readWriteToFile.writeToFile(data1, 'scrapA-data-' timestamp, 'json');
const data2 = await compare.compareData('./output/json/data.json',
'./output/json/scraped-data-' timestamp '.json')
let dataWithStockData = data2;
let mapDatas = dataWithStockData.map( obj => {
let finalObj = {
manufacturer: obj.manufacturer,
grade: obj.condition,
carrier: obj.carrier,
stock: obj.stock,
}
return finalObj;
});
await readWriteToFile.writeToFile(data2, 'data-with-stock-' timestamp, 'csv'); });
});
}
Then to catch the errors , you put the wrapperFunc in a try catch like this :
try{
await wrapperFunc();
} catch(err){
// do what you want with err
}