Home > Mobile >  async / await run async functions sequentially in nodejs, puppeteer
async / await run async functions sequentially in nodejs, puppeteer

Time:12-13

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 
}
  • Related