i want to fetch data from outside of my project with axios. i do it in side of class but for some reason i retrieve data in promise object i use await and promise but eventually i receive data in [object promise].
const Online_Visitors_System = class OnlineVisitors {
constructor() {
// get VisitorIP
this.IP = this.fetchIP();
// config redis for key space notification
this.redis = Redis.createClient();
this.redis.on("ready", () => {
this.redis.config("SET", "notify-keyspace-events", "KEA");
});
PubSub.subscribe("__keyevent#0__:incrby");
}
async fetchIP() {
return new Promise((resolve, reject) => {
return axios
.get("https://api.ipgeolocation.io/getip")
.then(res => resolve(res.data.ip));
});
}
VisitorInter() {
console.log(this.IP);
}
};
module.exports = new Online_Visitors_System();
error that i encounter with it::
This is converted to "[object Promise]" by using .toString() now and will return an error from v.3.0
on.
Please handle this in your code to make sure everything works as you intended it to.
Promise { '51.38.89.159' }
Well you missed await in fews places, here is full correction:
const Online_Visitors_System = class OnlineVisitors{
constructor(){
// get VisitorIP
this.fetchIP().then(ip => this.IP = ip);
// config redis for key space notification
this.redis = Redis.createClient();
this.redis.on('ready',()=>{
this.redis.config('SET',"notify-keyspace-events",'KEA')
})
PubSub.subscribe("__keyevent#0__:incrby")
}
fetchIP(){
return new Promise((resolve,reject)=>{
axios.get('https://api.ipgeolocation.io/getip')
.then(res=>resolve(res.data.ip))
})
}
VisitorInter(){
console.log(this.IP)
}
};
Since the method fetchIP is an async function you need also await when calling it,
so: this.IP = await this.fetchIP().
But since you are in construcot you can't use await so the solution is to use chaning:
this.fetchIP().then(ip => this.IP = ip);
Note that when initating new Promise you need to give it an async function, because inside that you are awating other methods.
You are assigning the promise of an IP address into this.IP.
You will need to .then the promise to get the actual IP address; it might or might not be available by the time VisitorInter() or anything else that needs the IP address is called.
class OnlineVisitors {
constructor() {
this.ipPromise = this.fetchIP();
// redis stuff elided from example
}
async fetchIP() {
const resp = await axios.get("https://api.ipgeolocation.io/getip");
return resp.data.ip;
}
async VisitorInter() {
const ip = await this.ipPromise; // this could potentially hang forever if ipgeolocation.io doesn't feel like answering
console.log(ip);
}
};
module.exports = new OnlineVisitors();
Related
So I am creating a module with a class method(schedule) with async function awaiting the return
//SCHEDULER.JS//
class Schedule {
constructor(project_id, queue_id) {
this.project_id = project_id;
this.queue_id = queue_id;
}
//ASYNC METHOD 1
schedule = async (date, rquest) => {
const project = this.project_id;
const queue = this.queue_id;
const location = "us-central1";
const url = rquest.url;
const payload = rquest.body;
// Construct the fully qualified queue name.
const parent = client.queuePath(project, location, queue);
const task = {
httpRequest: {
httpMethod: rquest.method,
url,
headers: rquest.headers,
},
};
try {
const request = await { parent, task };
const [response] = await client.createTask(request);
console.log("<THIS IS THE PROJECT ID> :", response.name);
return `${response.name}`;
} catch (error) {
console.log("we have an error amigo!", error);
}
};
//ASYNC METHOD 2
delete = async (one) => {
return console.log("delete function", one);
};
I imported my module on main.js and used my method. Once the results returns, I need to use it as a parameter to another method(delete) on the module I created(Scheduler.js).
//main.js//
const task_id = scheduler.schedule(date, request);
scheduler.delete(task_id);
task_id is returning a promise and I can't execute scheduler.delete(task_id) because it is pending promise still.
Important: How can I handle this promise properly as I am only tasked to create the module and not the main.js. The people who would create the main.js would just be expected to run my methods without handling promise returns.
TLDR
task_id is returning a promise
If it's a promise you can await it
//main.js//
async function main () {
const task_id = await scheduler.schedule(date, request); // <--- THIS!
scheduler.delete(task_id);
}
main();
Await & promises:
In fact, the await keyword only works on promises (you can await non-promises but it is a no-op by design). That's the whole reason for await - an alternative way to use promises. Because of this functions marked with the async keyword always returns a promise.
Or if you prefer not to await then just use it as a promise:
//main.js//
scheduler.schedule(date, request)
.then(task_id => scheduler.delete(task_id));
You can create another function, which will be called from main.js, and inside this function call your actual function and in then function of Promise return the value.
Given the following code:
async #token() {
const value = await this.belcorp.getAccessToken();
console.log(value);
}
This code returns:
But if I try to return that same result in my constructor with this code:
constructor() {
const token = this.#token();
console.log(token);
}
async #token() {
return await this.belcorp.getAccessToken();
}
returns the following:
What should I do to retrieve only the previous object?
Aside from the issue of Promises in constructors, your code returns a Promise because that is what you told it to do: async functions return Promises. If you want the awaited Promise result instead, change the line to
const token = await this.#token();
Of course, you would need your constructor to be async in this case, so you will need to move your code outside your constructor.
You cannot make a class constructor async. Instead, just make your own static constructor method -
class MyThing {
constructor(token) { // cannot be async
this.token = token // make sync instead
}
static async token() { // make static
return new Promise(r =>
setTimeout(r, 1000, "tkn123") // demo token response
)
}
static async new () { // make async constructor
return new MyThing(await this.token()) // await token
}
}
const main = async () =>
{ console.log("loading...")
const x = await MyThing.new() // <-- MyThing.new()
console.log("got token:", x.token)
return "done"
}
main().then(console.log, console.error)
// loading...
// got token: tkn123
// done
I'm trying to make an constructor for multiple Redis connections, so i've started to try something.
I'm only getting back from has Promise { }, but if I do an console.log before the return I'm getting the real Value.
EDIT: Tried without async/await still don't work.
app.js
const rBredis = require("./redis");
const redis = new rBredis();
console.log(redis.has("kek"));
redis.js
const Redis = require("ioredis");
class BasicRedis {
constructor() {
// TODO
};
redis = new Redis();
async has(id) {
return await this.redis.exists(id)
.then( exists => {
// console.log(exists); works 0
return exists; // works not Promise { <pending> }
});
};
}
module.exports = BasicRedis;
I don't understand your question completely but I see a problem here.
You need to brush up your knowledge of Promises and Async await. You either use async
await or Promises (.then) syntax to make it work properly.
redis.js
class BasicRedis {
constructor() {
// TODO
};
redis = new Redis();
// You can either do it like this
has(id) {
return new Promise((res, rej) => {
this.redis.exists(id)
.then( exists => {
res(exists)
}).catch(err => {
rej(err.message)
});
})
};
// Or like this
has(id) {
return this.redis.exists(id)
};
}
In both cases, you can await/.then result in your app.js
// app.js
const rBredis = require("./redis");
const redis = new rBredis();
redis.has("kek").then(res => console.log(res))
EDIT - 1
If this is something that'd take time even 1 millisecond there's no way you're going to get the value right away. You need to use either async-await or promises. Or use a callback like this
redis.js
class BasicRedis {
constructor() {
// TODO
};
redis = new Redis();
has(id, callback) {
this.redis.exists(id)
.then( exists => {
callback(exists)
}).catch(err => {
callback(err.message)
});
};
}
app.js
const rBredis = require("./redis");
const redis = new rBredis();
redis.has("kek", (res) => console.log(res))
Here's reference to Promises MDN and Async Await MDN
Hope it helps.
I am trying to do function chaining in a Javascript class by returning this after each method, but somehow, it does not work..:
let sql = require('mssql');
let {logger} = require('../utils/logger');
let config = require('config');
//mssql_stellenanzeigen_config = config.get('stellenanzeigen');
mssql_doublettencheckui_config = config.get('doublettencheckui');
class MSSQLConnectionObject {
constructor(configuration) {
this.configuration = configuration;
this.connection = undefined;
this.requestObject = undefined;
}
async build() {
let pool;
try {
pool = await new sql.ConnectionPool(this.configuration).connect();
console.log("Connection established!: ", pool);
} catch(e) {
logger.error("No SQL Database config or wrong config. Can't establish connection to MSSQL Server. " + e);
}
this.requestObject = await new sql.Request(pool);
return this;
}
static async connect(config) {
let pool;
try {
pool = await new sql.ConnectionPool(config).connect();
console.log("Connection established!: ", pool);
} catch(e) {
logger.error("No SQL Database config or wrong config. Can't establish connection to MSSQL Server. " + e);
}
this.requestObject = await new sql.Request(pool);
return this;
}
async getBuchungsquelle() {
const query = `SELECT * FROM buchungsquelle`;
return await this.requestObject.query(query).then((result) => console.log(result)).catch(err => console.log(err));
}
}
module.exports = {
MSSQLConnectionObject
}
let query= `select * from buchungsquelle`;
let a = new MSSQLConnectionObject(mssql_doublettencheckui_config);
a.build().getBuchungsquelle();
I get an error:
a.build().getBuchungsquelle();
TypeError: a.build(...).getBuchungsquelle is not a function
why does this not work? Is there an error in how to return this from my functions?
TypeError: a.build(...).getBuchungsquelle is not a function
build is an async function. When you say return this, it creates a function which returns a promise that resolves to this, not a function that returns this.
So to use it you would need to wait for the promise to resolve and then call the next function in sequence.
a.build().then( x => x.getBuchungsquelle() )
It doesnt work because your function is Async.
You are not actually returning a instance of MSSQLConnectionObject but a instance of Promise<MSSQLConnectionObject>.
Async Chaining:
Check out this Stackoverflow post to get a nice example of async chaining!
I've read that having an async inside a Promise is anti-pattern for async/await. The code below works, but I am curious how else to achieve the same result without having async in Promise.
If I remove it, the linter would tell how I can't use await in my mongodb query. If I remove the await in the mongodb query, then it wouldn't wait for the result.
export const getEmployees = (companyId) => {
return new Promise(async (resolve, reject) => {
const employees = await Employees.find(
{ companyId },
);
// other logic here...
resolve({
employees,
});
});
Thanks.
async functions automatically return Promises already, which resolve with whatever expression is eventually returned. Simply make getEmployees an async function:
export const getEmployees = async (companyId) => {
const employees = await Employees.find(
{ companyId },
);
// other logic here...
return { employees };
};
(but make sure to catch in the consumer of getEmployees just in case there's an error)
As #CertainPerformance answered, that is perfect way to retrieve data from mongoDB using async/await, I would like to add some more information about how to handle errors in this case for correctness of the system, and better error handle to return better status to the client about his request.
I'd say it , you usually want to catch all exceptions from async/await call.
try {
const employees = await Employees.find({
companyId
});
// You can add more logic here before return the data.
return {
employees
};
} catch (error) {
console.error(error);
}
Now let's check the ways we can handle our errors that might occur.
Handle error inside error scope.
Assign a default value to the variable in the catch block.
Inspect error instance and act accordingly.
This is the most common way to handle errors in those cases and most elegant way in my opinion.
Handle error inside error scope:
export const getEmployees = async (companyId) => {
try {
const employees = await Employees.find({
companyId
});
// You can add more logic here before return the data.
return {
employees
};
} catch (error) {
console.error(error);
}
};
Assign a default value to the variable in the catch block:
export const getEmployees = async (companyId) => {
let employees;
try {
employees = await Employees.find({
companyId
});
// You can add more logic here before return the data.
employees = employees;
} catch (error) {
console.error(error);
}
if (employees) { // We received the data successfully.
console.log(employees)
// Business logic goes here.
}
return employees;
};
Inspect error instance and act accordingly:
export const getEmployees = async (companyId) => {
try {
const employees = await Employees.find({
companyId
});
// You can add more logic here before return the data.
return {
employees
};
} catch (error) {
if (error instanceof ConnectionError) {
console.error(error);
} else {
throw error;
}
}
};
Some more explanations about async await and more useful methods that you can find in those answers.
How run async / await in parallel in Javascript