How to rewrite a function under async/await? - javascript

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
})
}

Related

Attempting to retrieve JSON data results in [ Promise { <pending> }, Promise { <pending> } ]

I am attempting to retrieve the JSON data stored in the following API:
https://api.hatchways.io/assessment/blog/posts
Using node.js and https requests, I constantly receive an array of [ Promise { }, Promise { } ]. Unfortunately, I can only search by one tag at a time, and I have to retrieve a list of posts that has at least one tag from a list of provided tags, before sorting the posts. My code is below:
const express = require('express');
const app = express();
app.get("/api/ping", (req, res) => {
res.status(200).send("{\"success\": true}");
})
app.get("/api/posts", (req, res) => {
const tags = req.query.tags;
const sortBy = req.query.sortBy;
const direction = req.query.direction;
if (!tags) res.status(400).send("Must provide at least one tag.");
let tag_array = tags.split(',');
let posts_array = [];
tag_array.forEach(tag => {
let posts = getPost(tag);
posts_array.push(posts);
})
console.log(posts_array);
})
app.listen(3000, () => console.log("Listening on port 3000..."));
function getPost(tag) {
const https = require('https');
return new Promise( (resolve, reject) => {
const options = {
hostname: 'api.hatchways.io',
path: `/assessment/blog/posts?tag=${tag}`
}
let body = [];
const req = https.request(options, res => {
res.on('data', data => {
body.push(data);
});
res.on('end', () => {
try {
body = JSON.parse(Buffer.concat(body).toString());
} catch (error) {
reject(error);
}
resolve(body);
});
});
req.on('error', error => {
reject(error);
});
req.end();
}).then(function(data) { return data; }, function(error) { console.log(error) });
}
the getPost method is returning a promise, just do this:
app.get("/api/posts", async (req, res) => {
const tags = req.query.tags;
const sortBy = req.query.sortBy;
const direction = req.query.direction;
if (!tags) res.status(400).send("Must provide at least one tag.");
let tag_array = tags.split(',');
const promises = [];
tag_array.forEach(tag => {
promises.push(getPost(tag))
});
posts_array = await Promise.all(promises)
console.log(posts_array)
})
Just wait for all promises to resolve using the await keyword.
app.get("/api/posts", async (req, res) => { // Add the async keyword
//... Skipped some code for concision
tag_array.forEach(tag => {
let posts = getPost(tag);
posts_array.push(posts);
})
await Promise.all(posts_array) // Add this to await all promises to resolve
console.log(posts_array);
})

Chaining Functions Does not Work Synchronously

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)
}
}

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

Passing multiple query objects with res.render

I want to pass multiple query objects with res.render() inside my route.js. I have a select.js which contains the SQL statements and delivers the objects to my route.js. This works fine until I want to pass multiple query objects with res.render().
Any ideas on how I can pass multiple objects at once?
snippet route.js (I need to pass get_PriceData here as well)
I already query get_KategorieData but I have no clue how to handle multiple queries in one route.
router.get('/edit', (req, res, next) => {
var speisenEintragenData = {};
db.get_KategorieData()
.then(({ data: kategorie_data }) => {
res.render('speiseEintragen', { kategorie_data }); //maybe putting res.render() after the db.get?
})
.catch((error) => {
console.log(error);
});
});
select.js
const db = require('./config');
//KATEGORIEN LADEN
const get_KategorieData=()=>{
var sql = 'SELECT * FROM Kategorie';
return new Promise((resolve,reject) => {
db.query(sql, function (err, data, fields) {
if (err) reject(err);
resolve({data});
});
})
}
//PREISE LADEN
const get_PriceData=()=>{
var sql = 'SELECT * FROM preise';
return new Promise((resolve,reject) => {
db.query(sql, function (err, data, fields) {
if (err) reject(err);
resolve({data});
});
})
}
module.exports={
get_KategorieData,
get_PriceData
}
There are two ways to go about this. One is to stick with promises and other is to use async/await.
Using promise
Create a new function to query database. This is if the module you are using does not support async/await and requires a callback.
const query = ( sql ) => {
return new Promise(( resolve, reject) => {
db.query(sql, function (err, data, fields) {
if (err) reject(err);
resolve(data);
});
})
}
// and then you can write an async/await function to call n queries like
const get_data = async () => {
const sql1 = '...';
const a = await query( sql1 );
const sql2 = '...';
const b = await query( sql2 );
....
....
....
const sqln = '...';
const n = await query( sqln );
return { a ,b,... ,n};
}
Or with async/await you can directly call db.query and use the response
const get_data = async () => {
const sql1 = '...';
const res_1 = await db.query(sql1);
const sql2 = '...';
const res_2 = await db.query(sql2);
return { a: res_1 ,b: res_2 };
}
router.js can rewritten as
router.get('/edit', async (req, res, next) => {
const {a:rename_a,b:rename_b and so on}=await db.get_data();
res.render('view', { rename_a,rename_b and so on })
});

REST API calls using async await

Here's my code snippet
var clients = require('restify-clients');
async function callApi(val){
const client = clients.createJsonClient({ url: apiUrl });
await client.get('/my/url', (err, req, res, obj) => {
if (err) {
return err;
} else {
return obj;
}
});
}
I've tried a few ways of calling it, but they all aren't working
First way:
var results = await callApi(val);
Second way:
var results = callApi(val).then(data => {
console.log(data);
})
client.get doesn't return a promise, you can't use await on a function which doesn't return a promise (honestly you can, but it doesn't make sense). The correct solution here is to promisify client.get and return a promise:
function callApi(val) {
const client = clients.createJsonClient({ url: apiUrl });
return new Promise((resolve, reject) => {
client.get('/my/url', (err, req, res, obj) => {
if (err) {
reject(err);
} else {
resolve(obj);
}
});
});
}
// Usage
let results = await callApi(val);
Try to remove await from results
var results = callApi(val);

Categories