How to return Data from readFileAsync - node.js

I have a function that needs to read from a file, then convert it to an json object with JSON.parse(string) and lastly return it to be used elsewhere.
this object is written to a txt file using JSON.stringify():
let User = {
Username:"#",
Password:"#",
FilePaths:[
{Year:'#', Month:'#', FileName:'#'}
]
}
the writing works fine, my problem is the reading,
Here is my code:
const readFileAsync = promisify(fs.readFile);
async function GetUserData(User) {
const Read = async () => {
return await (await readFileAsync('UserData\\'+User.Username+'\\UserData.txt')).toString();
}
return Read().then(data=>{return JSON.parse(data)})
}
console.log(GetUserData(User));
The result I get back is :
Promise {[[PromiseState]]: 'pending', [[PromiseResult]]: undefined}
How can I make this work so

In this instance, GetUserData returns a promise, so you'll need to use .then to get the data once resolved.
GetUserData(User).then(data => {
// do something with data
});
Alternatively, fs has a sync function you can use, rather relying on readFile (which is async), use readFileSync. Usage below:
function GetUserData(User) {
const data = fs.readFileSync('UserData\\'+User.Username+'\\UserData.txt').toString();
return JSON.parse(data);
}
console.log(GetUserData(User));

Related

NodeJs Returning data from async fetch on a variable to reuse

I'v been searching around for a few hours (with no success) on how to have an async function return a result, store it in a variable outside the function and reuse that data.
My issue is that I fetch the same data over and over in a few of my functions which seems unnecessary.
Basically this is what I want, and right now it's returning a promise.
let leads;
try {
var result = await fetch('http://localhost:3000/lds');
leads = await result.json();
return leads;
} catch (e) {
// handle error
console.error(e)
}
}
var results = readDb();
console.log(results);
For example, initially I run a function fetch the data and create a table.
Secondly I run another function that fetches the same data to create pagination buttons.
Thirdly I run another function that fetches the same data, yet again, and listens for the pagination button click to show the data of the corresponding page number.
Ideally I would fetch the data only once.
Thanks in advance!
We can define leads outside the function and check if it's necessary to fetch it:
let leads;
const getLeads = async function() {
try {
if (!leads) { // fetch leads only they weren't already loaded
const result = await fetch('http://localhost:3000/lds');
leads = await result.json();
}
return leads;
} catch (e) {
// handle error
console.error(e)
}
}
Since you are using async/await you need to await the value, however it is only available in an async function. You can reuse a variable outside the function to store the value once it is loaded.
// reuse leads variable
let leads;
// async function to populate/return leads
async function readDb() {
// only populate if it is undefined
if (typeof leads === 'undefined') {
const result = await fetch('http://localhost:3000/lds');
leads = await result.json();
}
// return just loaded or referenced value
return leads;
}
// call the function asynchronously
(async function(){
// await the results here inside an async function
const results = await readDb();
console.log(results);
}());

cannot make an async function using sequelize

I'm trying to get information from my model but it always returns me Promise { <pending> } or undefined (on all the ways I had tried)
Heres the code that I'm trying to use to retrieve information from DB
const cnabBody = require('../controller/cnabBody');
let resultado = cnabBody.encontrarUm().then((r) => {
console.log(r);
});
Heres my controller
const CnabBody = require ('../model/cnabBody');
exports.encontrarUm = async () => {
const { nome_campo } = await CnabBody.findOne({where:{nome_campo: "Nome do Campo"}});
return nome_campo;
}
I would need to know more about the object structure that's resolved from the findOne function, but it sounds like the nome_campo object being returned is a Promise object rather than a value. If that's the case then you'd also have to await on the nome_campo (assuming it's not undefined).
If CnabBody.findOne() returns this:
{
nome_campo: somePromise
}
then you should either change findOne to await on that Promise and send back the object it resolves to, or you need to await on it after receiving it in your controller. The latter could be done like this:
const CnabBody = require ('../model/cnabBody');
exports.encontrarUm = async () => {
const { nome_campo } = await CnabBody.findOne({where:{nome_campo: "Nome do Campo"}});
if (nome_campo) return await nome_campo; // <--- add await here if defined
}
However I'd say it's nicer if findOne could be changed (assuming you have access to the code) so that calling await CnabBody.findOne() returned the actual result and not a Promise. Having Promise that resolves another Promise seems redundant, but if you are not the author of findOne then you might not have the option to change its resolved object.
In your controller change const { nome_campo } to const nome_campo. it will work
const CnabBody = require ('../model/cnabBody');
exports.encontrarUm = async () => {
// const { nome_campo } = await CnabBody.findOne({where:{nome_campo: "Nome do Campo"}}); <== problem is here
const nome_campo = await CnabBody.findOne({where:{nome_campo: "Nome do Campo"}});
return nome_campo;
}
I was calling my async functions inside a function that wasnt async soo when i tried any await method it wasnt awaiting or returning a error soo i changed my first line
wb.xlsx.readFile(filePath).then(function(){
to
wb.xlsx.readFile(filePath).then(async function(){
soo my code looks like this now and it is working fine. (:
wb.xlsx.readFile(filePath).then(async function(){
var sh = wb.getWorksheet("Sheet1");
// console.log(sh.getCell("A1").value);
const field = await cnabContent.findOne({where: {nome_campo: "Nome do Campos"}});
console.log(field);
});
Thanks for all that tried to help me, made me do alot of searchs and read about promises, async and await and get this solution.

Async/Await and Then not working in my case

I have a function which contains a thousand of objects in an array:
function Alltransaction(transactionArray) {
transactionArray.map(async (transaction) => {
dataAgainsthash = await web3.eth.getTransaction(transaction)
TransactionObject = {
transactionHash : transaction,
from : dataAgainsthash.from
};
transactionArray.push(TransactionObject)
console.log("transaction array", transactionArray)
});
}
then i have another function which stores these thousands of object array into db
function saveTransactionToDb() {
console.log("after loop",transactionArray)
transactionss = new Transaction({
blockNumber : blockNumbers ,
transactions : transactionArray
})
// Now save the transaction to database
await transactionss.save();
// console.log("save to database")
}
then I call this in my router
await Alltransaction(transactionArray);
await saveTransactionToDb();
and I also try
Alltransaction(transactionArray).then(saveTransactionToDb())
But it always runs saveTransactionToDb() before the array of object populates the Alltransaction() method
have you try the async keyword before saveTransactionToDb and Alltransaction functions??
async function Alltransaction(transactionArray){
// your code
}
async function saveTransactionToDb(){
// your code logic*
await transactionss.save();
}
First, in Alltransaction the promise must be returned as well. In your code the function starts some processes but doesn't not await on it. Also, do not push the promises to the original array. I'm not sure what you were trying to accomplish there. Because mapping over the array gives you an array of promises, you can unify all of them with Promise.all().
function Alltransaction(transactionArray) {
const promises = transactionArray.map(async (transaction) => {
dataAgainsthash = await web3.eth.getTransaction(transaction)
const TransactionObject = {
transactionHash : transaction,
from : dataAgainsthash.from
};
return TransactionObject;
});
return Promise.all(promises);
}
Change saveTransactionToDb to receive an array instead of using the original array.
Then you'll be able to call it as:
const t = await Alltransaction(transactionArray);
await saveTransactionToDb(t);
Your second try it's not correct:
Alltransaction(transactionArray).then(saveTransactionToDb())
It's the same as:
const t = Alltransaction(transactionArray);
const s = saveTransactionToDb();
t.then(s)
That's why saveTransactionToDb doesn't way for transactions to complete. To use then, just pass the function without calling it:
Alltransaction(transactionArray).then(saveTransactionToDb)

NodeJS - read CSV file to array returns []

I'm trying to use the promised-csv module (https://www.npmjs.com/package/promised-csv) to read the rows of a CSV file to an array of strings for a unit test:
const inputFile = '.\\test\\example_result.csv';
const CsvReader = require('promised-csv');
function readCSV(inputFile){
var reader = new CsvReader();
var output = [];
reader.on('row', function (data) {
//console.log(data);
output.push(data[0]);
});
reader.read(inputFile, output);
return output;
}
I would like to call this function later in a unit test.
it("Should store the elements of the array", async () => {
var resultSet = readCSV(inputFile);
console.log(resultSet);
});
However, resultSet yields an empty array. I am also open to use any other modules, as long as I can get an array of strings as a result.
The code should look something like this, according to the docs.
const inputFile = './test/example_result.csv';
const CsvReader = require('promised-csv');
function readCSV(inputFile) {
return new Promise((resolve, reject) => {
var reader = new CsvReader();
var output = [];
reader.on('row', data => {
// data is an array of data. You should
// concatenate it to the data set to compile it.
output = output.concat(data);
});
reader.on('done', () => {
// output will be the compiled data set.
resolve(output);
});
reader.on('error', err => reject(err));
reader.read(inputFile);
});
}
it("Should store the elements of the array", async () => {
var resultSet = await readCSV(inputFile);
console.log(resultSet);
});
readCSV() returns a Promise. There are two ways that you can access the data it returns upon completion.
As Roland Starke suggests, use async and await.
var resultSet = await readCSV(inputFile);
This will wait for the Promise to resolve before returning a value.
More here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await
Use Promise.prototype.then() - this is similar to async/await, but can also be chained with other promises and Promise.prototype.catch().
The most important thing to remember is that the function passed to .then() will not be executed until readCSV() has resolved.
readCSV().then((data)=>{return data}).catch((err)=>{console.log(err)})
More here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then

Proper way using async/await making parallel calls

I am struggling with how to do this properly in nodejs. This tries to do two things in parallel:
downloads a webpage using axios
creates a directory
When those are finished:
save result asynchronously to a file in de created directory
Then waits until done
const uuidv1 = require('uuid/v1')
const fs = require('fs')
const util = require('util')
const axios = require('axios')
const path = require('path')
const mkdir = util.promisify(fs.mkdir)
const writeFile = util.promisify(fs.writeFile)
const downloadPage = async (url='http://nodeprogram.com') => {
console.log('downloading ', url)
const fetchPage = async function() {
const folderName = uuidv1()
return axios
.all([
mkdir(folderName),
axios.get(url)
])
.then(axios.spread(function (f, r) {
writeFile(path.join(__dirname, folderName, 'file.html'), r.data);
}));
}
await fetchPage()
}
downloadPage(process.argv[2])
Your question and sample are looking contradictory. Question says, you need to make use of async and await to make parallel calls, but your sample code shows you need sequential calls instead of parallel.
Best use of Async/Awaits are for making sequential calls.
async function is a kind of shorthand function for 'Promise', were things are done implicitly like returning will be considered as 'resolve'.
await should always be within async function, add await on functions you need to wait for before proceeding further.
Syntax change in await function is, instead of
somePromiseFunctionCall().then( (someVarible) => {...}).catch(e => {})
you need to use
const asyncFunction = async (parameters) => {
try {
// First Function call that returns Promise / async
someVariable = await somePromiseFunctionCall();
// Second (sequential) call that returns Promise / async
someNewVariable = await someotherPromiseFunctionCall();
} catch(e) {
throw new Error(e);
}
}
Now, in your sample, if your requirement is to wait for axios to return and then create folder and then write the result to file, that can be done using async and await.
Change this:
writeFile(path.join(__dirname, folderName, 'file.html'), r.data);
to this:
return writeFile(path.join(__dirname, folderName, 'file.html'), r.data);
You need to return the promise from writeFile so it is added to the chain so that the promise you're returning from fetchPage() is linked to the writeFile() operation. As your code was originally, the writeFile() operation is proceeding on it's own and is not connected at all to the promise you were returning from fetchPage() so when you do:
await fetchPage()
it wasn't awaiting the writeFile() operation.
A cleaned up version could look like this:
const downloadPage = (url='http://nodeprogram.com') => {
console.log('downloading ', url)
// don't really need this separate fetchPage() function
const fetchPage = function() {
const folderName = uuidv1()
return axios
.all([
mkdir(folderName),
axios.get(url)
])
.then(axios.spread(function (f, r) {
return writeFile(path.join(__dirname, folderName, 'file.html'), r.data);
}));
}
return fetchPage()
}
Then, you would use it like this:
downloadPage().then(() => {
// page is downloaded now
});
Or, inside an async function, you could do:
await downloadPage();
// page is downloaded here
Note, that I removed several cases of async and await as they weren't needed. await fetchPage() wasn't doing you any good at the end of downloadPage(). From a timing point of view, that does the exact same thing as return fetchPage() and this way, you're actually resolving with the resolved value of fetchPage() which can be more useful. There did not appear to be any reason to use async or await in downloadPage(). Keep in mind that an async function still returns a promise and the caller of that function still has to use .then() or await on the return value from that function. So, using await inside of downloadPage() doesn't change that for the caller.

Resources