Chaining Functions Does not Work Synchronously - javascript

I query the database as follows:
const testMe = async () => {
const index = await _fetchNextIndex()
if (index === undefined) {
throw new Error('Next index could not fetched')
}
return 'Success'
}
const _fetchNextIndex = async () => {
return db.query("SELECT nextval(pg_get_serial_sequence('testme_table', 'id'))", (err, result) => {
if (err) {
throw new Error('Index could not generated')
}
return result.rows[0]
})
}
db is defined as:
const {Pool} = require('pg')
const pool = new Pool()
module.exports = {
query: async (text, params, callback) => {
return await pool.query(text, params, callback)
}
}
My code doesn't w work synchronously. index is undefined and error is thrown. However, when I debug the application I see that this line is called after a time later:
return result.rows[0]
What I miss?
EDIT 1: I've added async and await into query function.
EDIT 2: I've also removed the callback.
const {Pool} = require('pg')
const pool = new Pool()
module.exports = {
query: async (text, params) => {
return await pool.query(text, params)
}
}

Related

Node.js fs.access returns undefined no matter what

Here's the code:
import * as path from 'path';
import * as fs from 'fs';
const doesPathExist = async (path: string) => {
return await fs.access(path, fs.constants.R_OK, (err) => {
return err ? false : true;
});
};
const someFunc = async (documentName: string) => {
const documentPath = path.join(__dirname, documentName);
const pathExists = doesPathExist(documentName);
};
The function doesPathExistseems to return Promise<void>, making the pathExists variable undefined no matter the outcome. I've tried initializing a temp variable at the top of the function before running fs.access and changing its value inside the callback but still no luck.
The issue is with fs.access, this function does not return a Promise or anything else.
There are a few options to solve it.
you can always use fs.accessSync()
const doesPathExist = async (path: string) => {
try {
fs.accessSync(path, fs.constants.R_OK)
return true
} catch (e) {
return false
}
};
Use fs.promises
const fsPromises = fs.promises;
const doesPathExistB = async (path: string) => {
try {
await fsPromises.access(path, fs.constants.R_OK)
return true
} catch (e) {
return false
}
};
// OR
const doesPathExistA = async (path: string) => {
return new Promise(async (resolve) => {
await fsPromises.access(path, fs.constants.R_OK)
.then(() => resolve(true))
.catch(() => resolve(false))
})
};

Second function not called asynchronously in nodejs

I am trying to call some function using a single express router , I want to call them in order, meaning that I don't want getLaps() function to execute before get streams function has done all the work , so I tried to use some solutions I found on the internet but it didn't work, the second function doesn't execute. Please help.
Here is my code :
router.get("/", async (req, res,done) => {
res.status(201).send('created user')
return getLaps(function () {
getStreams(function () {
});
});
// await getStreams();
// await getLaps();
// console.log("hey")
});
Here is the get laps function :
function getLaps(req) {
const access_token = '75f2d92fdc445033312854d775e039b6c5bf04e7';
//for test 3756582581,
const idL = [5567017025, 5566531480];
const stravaClient = StravaClientService.getClient(access_token);
const activityService = StravaActivityService(stravaClient);
var params = {
TableName: "run-id",
Key: {
"id": "15428785",
}
};
console.log("cool laps")
docClient.get(params, async function (err, data) {
if (err) {
console.log("Error", err);
} else {
}
idL.map((id, index) => setTimeout(() => activityService.listLaps(id), (5 + index) * 60)
)
//data.Item.json
});
}
and the streams function :
function getStreams(req) {
const idS = [
5567017025, 5566531480
];
const stravaClient = StravaClientService.getClient(access_token);
const activityService = StravaActivityService(stravaClient);
var params = {
TableName: "run-id",
Key: {
"id": "15428785",
}
};
console.log("cool streams")
docClient.get(params, async function (err, data) {
if (err) {
console.log("Error", err);
} else {
idS.map((id, index) => setTimeout(() => activityService.streamActivity(id), (5 + index) * 60))
console.log("got the streams")
}
});
}
in your getStream and getLaps function return promises instead of other object/Stuff like
async function getStream(){
return new Promise(async (resolve, reject){
//Do something
//where you want to return something just call resolve function like
resolve()
//if you want some output of getStream() just pass it to resolve function
//const result = 'I'm result'
resolve(result)
})
}
do same thing with the laps function and in your router call them with await keyword

readFileSync returns undefined when trying to read data from files

I created multiples functions under a directory called data and fill them with some random data returned by a function called generatedRandomData.
To create multiple files I wrote these functions:
const createFile = (fileName, data) => {
if (fs.existsSync(fileName)) throw new Error('Filename already exists');
fs.writeFile(fileName, data, {
encoding: 'utf8',
flag: 'w',
}, (error) => {
if (error) return error;
console.log('File created successfully');
return null;
});
};
const createFiles = (dirPath, sizeList) => {
if (sizeList && !sizeList.length) throw new Error('The list of size should not be empty');
const fileCreationPromises = sizeList.map(async (size) => {
const data = generateRandomData(size);
const fileName = resolve(dirPath, `./data_${size}.txt`);
await createFile(fileName, data);
});
return Promise.all(fileCreationPromises);
};
Then I call the function generateData in order to generate random data and call the functions described above then create the files:
const generateData = async (dirPath, sizeList) => {
if (!dirPath) throw new Error('No directory path was provied');
if (!sizeList || (sizeList && !sizeList.length)) throw new Error('Size list should not be empty');
await createFiles(dirPath, sizeList);
};
I call another function called execute which reads data from those file in order to continue the treatment:
const execute = async (func, dirPath, label) => {
const files = fs.readdirSync(dirPath);
const result = [];
if (files && files.length) {
for (const file of files) {
const filename = resolve(dirPath, `./${file}`);
const parsedData = readDataFromFile(filename);
const data = parsedData.split(',').map((d) => Number(d));
const { length } = data;
result.push({
label: length,
value: getExecutionTime(func, data),
});
}
}
await createFile(resolve(dirPath, `./${label}`), result);
};
Finally, I call the function initialize:
const { resolve } = require('path');
const fs = require('fs');
const { generateData, sizeList, execute } = require('../utils/helpers');
const { underscorePartial } = require('../main/partial');
const dirPath = resolve(__dirname, '../data');
const initialize = () => {
if (!fs.existsSync(dirPath)) {
fs.mkdir(dirPath, async (error) => {
if (error) throw error;
await generateData(dirPath, sizeList);
await execute(underscorePartial, dirPath, 'uExecutionTime.txt');
});
}
};
try {
initialize();
} catch (error) {
console.log(error);
}
However I realized that uExecutionTime.txt to be created in the final step contains undefined due to the function readDataFromFile which returns undefined.
I guess the readDataFromFile starts reading from files before the creation of data finished.Any suggestions to fix my code or are there anything missed or wrong in the code?
The problem is your createFile function. You care awaiting it while it doesn't return promise. It is a callback style. It should be wrapped in promise.
const createFile = (fileName, data) => {
if (fs.existsSync(fileName)) throw new Error('Filename already exists');
return new Promise((resolve, reject) => {
fs.writeFile(fileName, data, {
encoding: 'utf8',
flag: 'w',
}, (error) => {
if (error) reject(error);
console.log('File created successfully');
resolve(null);
});
});
};
Hope this resolves the issue.

Why I am getting undefined after calling fetchNotes

After calling fetchNotes from the addNote function it shows me undefined as push method is not defined in the addNote function
const fs = require('fs');
const fetchNotes = ()=>{
fs.readFile('data.json',(err,notes)=>{
if(err){
// return empty array if data.json not found
return [];
}else{
// return Object from data found data.json file
return JSON.parse(notes)
}
});
}
const saveNotes = (notes) =>{
fs.writeFile('data.json',JSON.stringify(notes),()=>{
console.log('Notes is successfully saved');
});
}
const addNote = (title, body)=>{
const note = {
title,
body
}
const notes = fetchNotes();
//Push method not defined
notes.push(note);
saveNotes(notes);
return note;
}
module.exports.addNote = addNote;
It returns undefined because when you are returning in the callback you are not exactly returning from the fetchNotes function itself.
Maybe you can use the readFileSync and don't use callback or maybe you can make it a promise and use async/await
const fetchNotes = () => {
return new Promise((res, rej) => {
fs.readFile('data.json', (err, notes) => {
if (err) {
// return empty array if data.json not found
res([]);
} else {
// return Object from data found data.json file
res(JSON.parse(notes));
}
});
});
}
const addNote = async (title, body) => {
const note = {
title,
body
}
const notes = await fetchNotes();
//Push method not defined
notes.push(note);
saveNotes(notes);
return note;
}
Alternatively, you can use utils.promisify
return JSON.parse(notes) does not store this value inside fetchNotes because it is asynchronous, so you get the content of the file later in time.
To do it asynchronously, you can use async/await :
const fetchNotes = () => {
return new Promise((resolve, reject) => {
fs.readFile('data.json', (err,notes) => resolve(JSON.parse(notes)));
})
}
const addNote = async (title, body) => {
// ...
const notes = await fetchNotes();
notes.push(note);
saveNotes(notes);
return note;
}
You can also do it synchronously :
const fetchNotes = () => JSON.parse( fs.readFileSync('data.json') );
const notes = fetchNotes();

How to rewrite a function under async/await?

I want to stop using the async library, replacing it with vanilla js.
const async = require('async')
function getTopicsData(tids, Uid, callback) {
async.map(tids, (tid, next) => {
redis.hgetall(`topic:${tid}`, (err, topics) => {
redis.sismember(`topic:${tid}:subscribers`, Uid, (err, subscriber) => {
topics.subscriber = !!subscriber
next(false, topics)
})
})
}, callback)
}
module.exports = getTopicsData
The solution I would implement would also include bluebird. Here is how I would use it.
const Promise = require('bluebird')
const hgetall = Promise.promisify('redis.hgetall')
const sismember = Promise.promisify('redis.sismember')
module.exports = async function (tids, Uid) {
return Promise.map(tids, async function (tid) {
let {topics, subscriber} = await Promise.props({
topics: hgetall(`topic:${tid}`),
subscriber: sismember(`topic:${tid}:subscribers`, Uid)
})
topics.subscriber = !!subscriber
return topics
})
}

Categories