Async/Await function not waiting for promise to end - javascript

let myObject = ( () => {
let run = async() => {
foo = new genericFunction();
status = await foo.myFunction();
}
})();
Another FIle.js
let genericFunction = function() {
this.getData = async () => {
$.getJSON("path/to/file.json", function (data) {
console.log("Apple", data.name);
return data.name;
}).fail(function(jqxhr, textStatus, error){
console.log("Loading Error :: ", error);
)};
}
this.myFunction = async () => {
let data = this.getData();
console.log('DATAA:::', data); //This should be the first output
}
}
The problem is:
status is always = undefined because somehow it returns before getJSON executes and I don't know why.

Another FIle.js should be like:
let genericFunction = function() {
this.getData = async () => {
var result = await $.getJSON("path/to/file.json", function (data) {
console.log("Apple", data.name);
return data.name;
}).catch(function(jqxhr, textStatus, error){
console.log("Loading Error :: ", error);
)};
return result;
}
this.myFunction = async () => {
let data = this.getData();
console.log('DATAA:::', data); //This should be the first output
}
}

Here's a simplified example using your code but with a couple of changes:
1) Uses a class
2) You're not returning anything from myFunction so there's no reason to assign something to status - just call the function.
3) getData doesn't need an async keyword, and you need to return the promise (in this example I mocked up a AJAX call that returns data after a second) from the function for it to work.
4) You do need to await for the promise to return in myFunction. You have async there, you just need to add the await keyword too.
class GenericFunction {
getData() {
return new Promise(resolve => {
setTimeout(() => resolve('Hello World'), 2000);
});
}
async myFunction() {
let data = await this.getData();
console.log('DATAA:::', data);
}
}
(async () => {
const foo = new GenericFunction();
foo.myFunction();
})();

Related

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

How can I implement memoize method on an async function in JavaScript?

I have been trying to write the implementation of the memoize function in JavaScript. I was asked this in an interview question and haven't been able to put it out of my mind since. I would really appreciate some help with this.
Given a function in which we are making an API call -
function getSomeData(foo, callback) {
var uri = 'http://localhost?foo=' + foo ;
someAPIUri(uri, function onResponse(error, response, body) {
callback(error, body);
});
}
Instead of using an API, using setTimeout for async functionality -
function getSomeData(foo, callback) {
setTimeout(()=> {
console.log('async request');
callback(2 * foo);
}, 1000);
}
If we make a call like below twice, that means two async calls made, so we need to create a memoize function which caches the response for some input and respond with that in any subsequent call.
getSomeData(1, (response) => {
console.log('getSomeData', response);
})
I wrote this function -
function memoize(fn) {
const cache = {};
return async function() {
const args = JSON.stringify(arguments);
console.log('arguments passed to memoize fn: ', args);
console.log('cache data: ', cache[args]);
cache[args] = cache[args] || fn.apply(undefined, arguments);
return cache[args]
}
}
const memoizedGetSomeData = memoize(getSomeData);
const callback_fn = (response) => {
console.log('callback response: ', response);
}
memoizedGetSomeData(1, callback_fn);
memoizedGetSomeData(1, callback_fn);
This is not working as the async call is getting made for each memoizedGetSomeData call.
I would really appreciate some input to get it working and improving my understanding.
This is a codepen of the code - link
The console log:
"arguments passed to memoize fn: " "{'0':1}"
"cache data: " undefined
"arguments passed to memoize fn: " "{'0':1}"
"cache data: " undefined
"async request"
"callback response: " 2
"async request"
"callback response: " 2
The only real issue (from what I see) is that getSomeData is a poor mock of async functionality, as it doesn't return a promise.
function getSomeData(foo, callback) {
return new Promise((resolve, reject) => {
setTimeout(()=> {
console.log('async request');
resolve(callback(2 * foo));
}, 1000);
});
}
function memoize(fn) {
const cache = {};
return async function() {
const args = JSON.stringify(arguments);
console.log('arguments passed to memoize fn: ', args);
console.log('cache data: ', cache);
cache[args] = cache[args] || fn.apply(undefined, arguments);
return cache[args]
}
}
const memoizedGetSomeData = memoize(getSomeData);
const callback_fn = (response) => {
console.log('callback response: ', response);
}
memoizedGetSomeData(1, callback_fn);
memoizedGetSomeData(1, callback_fn);
Thanks #Bergi and #dave for the comments. I understood the problem with my code and how the memoize function should work like for an async function.
This is the final code with a basic implementation of Memoize on an async function -
function getSomeData(foo, callback) {
return new Promise((resolve, reject) => {
setTimeout(()=> {
console.log('async request');
resolve(callback(2 * foo));
}, 1000);
});
}
function memoize(fn) {
const cache = {};
return async function() {
const args = JSON.stringify(arguments);
cache[args] = cache[args] || fn.apply(undefined, arguments);
return cache[args]
}
}
const memoizedGetSomeData = memoize(getSomeData);
const callback_fn = (response) => {
return response;
}
// this should make async call
memoizedGetSomeData(1, callback_fn).then(response => console.log('response from async call: ', response));
// this should return response from the cache
memoizedGetSomeData(1, callback_fn).then(response => console.log('cached response: ', response));
// this should make async call (different argument)
memoizedGetSomeData(4, callback_fn).then(response => console.log('response from async call: ', response));
Log:
"async request"
"response from async call: " 2
"cached response: " 2
"async request"
"response from async call: " 8
I have updated the Codepen code as well.
function getSomeData(foo, callback) {
console.log('inside async call', foo)
setTimeout(() => callback(foo * Math.random(100)), 1000)
}
function memoize(fn) {
let cache = {};
return function() {
let key = JSON.stringify(arguments);
if (key in cache) {
return cache[key];
} else {
cache[key] = fn.apply(this, arguments);
return cache[key];
}
};
}
getSomeDatav2 = memoize(getSomeData);
getSomeDatav2(2, (r) => console.log(r));
getSomeDatav2(2, (r) => console.log(r));
getSomeDatav2(2, (r) => console.log(r));
getSomeDatav2(1, (r) => console.log(r));
getSomeDatav2(1, (r) => console.log(r));
getSomeDatav2(3, (r) => console.log(r));

How to call an asynchronous JavaScript function?

Can anyone please help me with the following, I am new to Async\Await in Javascript:
I have a trivial class:
function Thing()
{
}
Thing.prototype.ShowResult = function ()
{
var result = this.GetAsync();
alert(result);
}
Thing.prototype.GetAsync = async function ()
{
var result = await this.AsyncFunc();
return result;
}
Thing.prototype.AsyncFunc = async function ()
{
return new Promise(resolve => {
setTimeout(() => {
resolve(6);
}, 2000);
});
}
I call it like this:
var thing = new Thing();
thing.ShowResult();
I expected a delay of 2 seconds before seeing the result of 6.
Instead I immediately see:
[object Promise]
How can I correctly await the result? Thanks for any help.
You have to make the parent function consuming the async function async as well.
function Thing() {}
Thing.prototype.ShowResult = async function() { // add async
var result = await this.GetAsync(); // await the response
alert(result);
}
Thing.prototype.GetAsync = async function() {
var result = await this.AsyncFunc();
return result;
}
Thing.prototype.AsyncFunc = async function() {
return new Promise(resolve => {
setTimeout(() => {
resolve(6);
}, 2000);
});
}
Then you can call ShowResult
var thing = new Thing();
await thing.ShowResult();
But, if you're calling thing.ShowResult outside of an async function you'll have to use the Promise syntax since you can't await something that isn't in an async function. There's no concept of a "top level await" in JS. Yet.
var thing = new Thing();
thing.ShowResult().then( result => console.log(result) );
In JavaScript, async functions always return a Promise (this is why you see [object Promise]), which can be resolved either by calling its then method or by using the await keyword. For now, await can only be used inside async functions.
To apply this to your problem, you can do one of the following:
#1
Thing.prototype.ShowResult = function ()
{
this.GetAsync().then(alert);
}
thing.ShowResult();
#2
In this approach, ShowResult is also an async function. So what I wrote above also applies to it.
Thing.prototype.ShowResult = async function ()
{
var result = await this.GetAsync();
}
await thing.ShowResult();
Though AsyncFunc and GetAsync are async functions. ShowResult function is not. It is necessary for the parent function to be async as well. The below code returns 6.
function Thing()
{
}
Thing.prototype.ShowResult = async function ()
{
var result = await this.GetAsync();
alert(result);
}
Thing.prototype.GetAsync = async function ()
{
var result = await this.AsyncFunc();
return result;
}
Thing.prototype.AsyncFunc = async function ()
{
return new Promise(resolve => {
setTimeout(() => {
resolve(6);
}, 2000);
});
}
var thing = new Thing();
thing.ShowResult();
Your function GetAsync() return a promise to consume the promise you have to either use await or .then read more about async/await
function Thing() {}
Thing.prototype.ShowResult = async function() {
var result = await this.GetAsync();
alert(result);
}
Thing.prototype.GetAsync = async function() {
var result = await this.AsyncFunc();
return result;
}
Thing.prototype.AsyncFunc = async function() {
return new Promise(resolve => {
setTimeout(() => {
resolve(6);
}, 2000);
});
}
var thing = new Thing();
thing.ShowResult();
using .then
function Thing() {}
Thing.prototype.ShowResult = async function() {
var result = this.GetAsync().then((result)=>alert(result));
}
Thing.prototype.GetAsync = async function() {
var result = await this.AsyncFunc();
return result;
}
Thing.prototype.AsyncFunc = async function() {
return new Promise(resolve => {
setTimeout(() => {
resolve(6);
}, 2000);
});
}
var thing = new Thing();
thing.ShowResult();

Async module returning promise [object Promise]

I am trying to export the value with instrument variable. however data is returning as [object Promise] than object. How can I assign module variable with the final result rather than the promise object.
var instruments = {
data: async () => {
return new Promise((resolve, reject) => {
/// Respond after retrieving the data
resolve({result : "...." }
);
}
}
var symbols = async () => {
const res = await instruments.data();
return res;
}
module.exports.instrument = symbols().then((data) => {
console.log('data');
return data;
}).catch((e) => {
console.log('error');
return {}
});
It looks like you want a singleton cache. Here is a basic implementation
cache.js
let data = {}
module.exports = {
getData: () => {
return data
},
setData: newData => {
data = newData
return
},
}
No need for async here. I would separate this code with the code that retrieves data.
fetchData.js
const cache = require('./cache')
const fetchData = () => {} // fetch data code here
fetchData().then(data => {
cache.setData(data)
})
try this
var instruments = {
data: () => {
return new Promise((resolve, reject) => {
/// Respond after retrieving the data
resolve({result : "...." });
}
}
var symbols = async () => {
const res = await instruments.data();
return res;
}
module.exports.instrument = symbols;
then import instrument method to call and then call
const instrument = require("./filepath");
instrument().then((data) => {
console.log('data');
}).catch((e) => {
console.log(e);
});
If your async function instruments.data() called, it'll await return Promise.
just append await at return for your expected result.
var instruments = {
data: async () => {
return await new Promise((resolve, reject) => {
// Respond after retrieving the data
resolve({result : "...." });
}
}
or remove async. it's same as above.
var instruments = {
data: () => {
return new Promise((resolve, reject) => {
// Respond after retrieving the data
resolve({result : "...." });
}
}

How to access an object from another function in Javascript

I'm trying to get some data from an array and store store it in an object but I keep getting either an empty object or Promise { <pending> } in the logs. I'm using a global variable to store it and access it in another function. Not sure what i'm doing wrong.
var messageData = {};
const getNotifications = async () => {
let fcmObjects = await fcmTokens();
fcmObjects.forEach( (notificationData) => {
messageData = notificationData;
});
};
function getMessageData() {
console.log(messageData);
}
getMessageData();
getNotifications().then(function () {
console.log('All Done');
}).catch(function (error) {
console.log('Oops', error);
});
the console log is happening before the async method/Promise is being resolved. You should check it only after that. In other words, your code should be similar to:
getNotifications().then(function () {
getMessageData();
console.log('All Done');
}).catch(function (error) {
console.log('Oops', error);
});
If you do not want to call it inside getNotifications(), just get the Promise it returns and execute your call inside the .then() (option 1) or do an await (option 2). In code:
const notificationPromise = getNotifications();
// option 1
notificationPromise.then(getMessageData);
// option 2
await notificationPromise;
getMessageData();
A link to know more https://javascript.info/async about the topic.
Decoding your program line by line
var messageData = {};
is an object
const getNotifications = async () => {
let fcmObjects = await fcmTokens();
fcmObjects.forEach( (notificationData) => {
messageData = notificationData;
});
};
getNotifications is an async function.
function getMessageData() {
console.log(messageData);
}
getMessageData prints whatever is message data.
getMessageData();
you printed message data which is {}. Remember getNotfications is never called till now as the line are executed one by one.
getNotifications().then(function () {
console.log('All Done');
}).catch(function (error) {
console.log('Oops', error);
});
Now the above code call getNotification and run the function provided in then when the async call is completed. So you need to call getMessageData() in then function.
getNotifications().then(function () {
getMessageData();
console.log('All Done');
}).catch(function (error) {
console.log('Oops', error);
});
You execute getMessageData before getNotifications. You can use async/await approach
try {
await getNotifications();
getMessageData();
console.log('All Done');
} catch (error) {
console.log('Oops', error);
}
var messageData = [];
const getNotifications = async() => {
//let fcmObjects = await fcmTokens();
//fcmObjects.forEach((notificationData) => {
// messageData = notificationData;
//});
// simulate commentet above code
return new Promise((resolve,reject)=>{ messageData=['someMessage']; resolve()})
};
function getMessageData() {
console.log(messageData);
}
async function run() {
try {
await getNotifications();
getMessageData();
console.log('All Done');
} catch (error) {
console.log('Oops', error);
}
}
run();
You need to wait the getNotifications function to finish before you could log it's result to the console.
getNotifications is asynchronous, which means it won't run synchronously and the following lines of code
function getMessageData() {
console.log(messageData);
}
getMessageData();
may be executed before your getNotifications completes, thus your getMessageData() call doesn't print the wanted result.
First: your global variable messageData gonna be the last item in fcmObjects in this scenario. so make sure you provide a key or index for messageData object in fcmObjects.forEach( (notificationData) => {
messageData = notificationData;
});
Second:
when you call an Asynchronous operation you would not log it that way.
After all your code must be like this:
var messageData = {};
const getNotifications = async () => {
let fcmObjects = await fcmTokens();
fcmObjects.forEach( (index, notificationData) => {
messageData[index] = notificationData;
});
};
function getMessageData() {
console.log(messageData);
}
getNotifications().then(function () {
getMessageData();
console.log('All Done');
}).catch(function (error) {
console.log('Oops', error);
});

Categories