async trouble using javascript - javascript

I created an api that returns JSON. I am using javascript and what I am trying to do is save the .ContactID from the json and assign that value to the global variable contactID. I am new at this and I am sure my problem is that my code is not waiting for the data to come back from the server..
<script>
const contactID =getContactIDfromServer();
async function getContactIDfromServer(){
// Replace ./data.json with your JSON feed
fetch('https://cnx2zr39y8.execute-api.us-west-2.amazonaws.com/Production?Name=hector%20Salamanca').then(async response => {
return await response.json();
}).then (async data => {
// Work with JSON data here
var parsed = await JSON.parse(data);
//document.getElementById("demo").innerHTML = "This is inside function "+parsed.ContactID;
var stuff =await parsed.ContactID;
console.log('This is inside '+stuff);
return stuff;
}).catch(err => {
// Do something for an error here
});
}
console.log('this is outside '+contactID);
</script>

Not tested:
async function getContactIDfromServer() {
try{
const response = await fetch('https://cnx2zr39y8.execute-api.us-west-2.amazonaws.com/Production?Name=hector%20Salamanca')
const parsed = await response.json()
const stuff = parsed.ContactID
console.log('This is inside ' + stuff)
return stuff
} catch(error) {
throw error
}
}
This function should be called in an async context and awaited for its result

You can do
async function getContactIDfromServer(){
// Replace ./data.json with your JSON feed
try{
const response = await fetch('https://cnx2zr39y8.execute-api.us-west-2.amazonaws.com/Production?Name=hector%20Salamanca')
const data = await response.json();
let parsed = JSON.parse(data);
let stuff = parsed.ContactID;
console.log('This is inside ', stuff);
return stuff;
} catch(e) {
// Do something for an error here
}
}
And then call as
getContactIDfromServer().then(res => console.log(res))
That should work.

Related

Nodejs wait till async function completes and print the results

I want to wait on the HTTP POST request to complete and then return response to the caller function. I am getting Undefined when I print the received results.
I have defined post method as below:
// httpFile.js
const axios = require('axios');
module.exports = {
getPostResult: async function(params) {
console.log("getPostResult async called...");
var result = await axios.post("https://post.some.url", params)
.then ((response) => {
console.log("getPostResult async success");
return {response.data.param};
})
.catch ((error) => {
console.log("getPostResult async failed");
return {error.response.data.param};
});
}
}
And I am calling it in this way:
// someFile.js
const httpFile = require('./httpFile');
// Called on some ext. event
async function getPostResult() {
var params = {var: 1};
var result = await httpFile.getPostResult(params);
// Getting Undefined
console.log("Done Result: " + JSON.stringify(result));
}
I don't want to handle the .then and .catch in the calling function as I want to return the different values based on the POST result.
How should I wait for the response and get the return results.
In the above code I am getting the log statements as expected and "Done Result" get printed at the very end after the 'getPostResult' returns.
you are using both await & .then thats why it returns undefined.
this is how it should look
// httpFile.js
const axios = require('axios')
module.exports = {
getPostResult: async function (params) {
try {
const res = await axios.post('https://post.some.url', params)
return res.data
} catch (error) {
// I wouldn't recommend catching error,
// since there is no way to distinguish between response & error
return error.response.data
}
},
}
if you want to catch error outside of this function then this is way to go.
getPostResult: async function (params) {
const res = await axios.post('https://post.some.url', params)
return res.data
},

stored array outside of async function in nodejs fetch

How do I get the value of the failed array outside of the function? Because I need this array as an input for other functions.
failed = [];
async function fetchFromApi(i) {
var ApiEndpoint = "https://jsonplaceholder.typicode.com/todos/" + i
var httpRequest = {
method: "GET"
}
var response = await fetch(ApiEndpoint, httpRequest);
if (!response.ok) { // Necessary for error handling, fetch does not return an error if HTTP request fails
failed.push(i);
console.log(failed)
} else {
let symbolData = await response.json();
console.log(JSON.stringify(symbolData))
return JSON.stringify(symbolData);
}
};
fetchFromApi("abc")
console.log(failed)
The console.log("failed") in the code above gives me an empty array []. I want it to be getting ["abc"] when this variable being called outside of the function
UPDATE EDIT (new follow-up question):
I tried #SlothOverlord 's solution and it seems to work below is the example.
const myFunction = async (j) => {
failed = [];
async function fetchFromApi(i) {
var ApiEndpoint = "https://jsonplaceholder.typicode.com/todos/" + i
var httpRequest = {
method: "GET"
}
var response = await fetch(ApiEndpoint, httpRequest);
if (!response.ok) { // Necessary for error handling, fetch does not return an error if HTTP request fails
failed.push(i);
} else {
let symbolData = await response.json();
console.log(JSON.stringify(symbolData))
return JSON.stringify(symbolData);
}
};
await fetchFromApi(j)
return failed
}
myFunction("abc").then(data=>console.log(failed))
However, when I add in a forEach statement within the function, it breaks and returns an empty array again. See example below. What's going on here?
const myFunction = async (j) => {
failed = [];
async function fetchFromApi(arrays) {
arrays.forEach(async function(i) {
var ApiEndpoint = "https://jsonplaceholder.typicode.com/todos/" + i
var httpRequest = {
method: "GET"
}
var response = await fetch(ApiEndpoint, httpRequest);
if (!response.ok) { // Necessary for error handling, fetch does not return an error if HTTP request fails
failed.push(i);
// console.log(failed)
} else {
let symbolData = await response.json();
console.log(JSON.stringify(symbolData))
return JSON.stringify(symbolData);
}
});
}
await fetchFromApi(j)
// console.log(failed)
return failed
}
myFunction(["aaa", "abc"]).then(data=>console.log(failed))
You need to await the fetchFromApi("abc") function.
Async await only works INSIDE the function, not outside of it.
So what happened is:
fetchFromApi("abc") is called
console.log(failed) is empty
fetchFromApi("abc") finished
The solution is to wrap the function in async and await the fetchFromApi call
const myFunction = async () => {
//...
failed = [];
async function fetchFromApi(i) {
//...
}
await fetchFromApi("abc")
console.log(failed)
}
fetchFromApi is an async method, you need to await it if you want to see it's result logged.
JavaScript has a concurrency model based on an event loop, which is responsible for executing the code, collecting and processing events. when the async call will have it's result it will be placed in the callback queue and on the next iteration (tick), it will be popped out from there and placed in the execution stack to be processed. when you use await, the exection call will be halted at that point and will progress until the async call has it's result.
failed = [];
async function fetchFromApi(i) {
var ApiEndpoint = "https://jsonplaceholder.typicode.com/todos/" + i
var httpRequest = {
method: "GET"
}
var response = await fetch(ApiEndpoint, httpRequest);
if (!response.ok) { // Necessary for error handling, fetch does not return an error if HTTP request fails
failed.push(i);
console.log(failed)
} else {
let symbolData = await response.json();
console.log(JSON.stringify(symbolData))
return JSON.stringify(symbolData);
}
};
await fetchFromApi("abc")
console.log(failed)
JS event loop - https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop

Movie API:How Can I Return The Value?

I'm using The Movie Database API. And the problem that i can't solve is returning "keys" variable when i call the function with Movie's id.I'm new on JavaScript that's why i can't solve this. Hope someone can help me, thanks in advance.
const APIURL = "https://api.themoviedb.org/3/discover/movie?sort_by=popularity.desc&api_key=[MY API KEY HERE]&page-1";
getMovies(APIURL)
async function getMovies(url)
{
const resp = await fetch(url);
const respData = await resp.json();
showMovies(respData.results)
}
async function getTrailer(id)
{
const resp = await fetch(`https://api.themoviedb.org/3/movie/${id}/videos?api_key=[MY API KEY HERE]&language=en-US`);
const respDataa = await resp.json();
let results = respDataa.results;
let keys = results[0].key;
return keys;
}
function showMovies(movies){
movies.forEach(movie => {
const modals = document.createElement('div');
modals.classList.add('modal');
modals.innerHTML = ` <a target="_blank" href ="https://www.youtube.com/watch?v=${getTrailer(movie.id)}">Watch Trailer</a>`
}
}
Well, first of all, always hide your api keys if you're posting your code somewhere (even if it's a private repository, you shouldn't do it).
Secondly, if you want to return multiple keys, you can map the results to extract id from each of them and do a return:
async function getTrailer(id)
{
const resp = await fetch(`https://api.themoviedb.org/3/movie/${id}/videos?api_key=04c35731a5ee918f014970082a0088b1&language=en-US`);
const respDataa = await resp.json();
let results = respDataa.results;
return results.map(({ key }) => key);
}
Async functions return a Promise in JavaScript.
Simply add return keys at the end of your function.
Then you can do:
getTrailer(528085).then(data => {
// do something with the data
})
You can also handle errors:
getTrailer(528085)
.then(data => {
// do something with the data
})
.catch(err => {
/*
An error occured. You can use err.toString() to convert the error into a string
*/
})
If you want to get the returned data immediately from an async function(or a promise), put your logic inside an async function, then you can simply do:
let keys = await getTrailer(528085)
And, here is how to handle errors in async/await:
try {
let keys = await getTrailer(528085)
}
catch(err){
/*
An error occured. You can use err.toString() to convert the error into a string
*/
}
By the way, like Desiigner said, don't keep your API keys in the client. Anyone can see your API key. Use a server to return the API response to the client.
We have to await or.then the return (it’s a Promise).
function showMovies(movies) {
// make the forEach callback async
movies.forEach(async (movie) => {
console.log(getTrailer(movie.id)) // Promise {<pending>}
const trailer = await getTrailer(movie.id);
console.log({ trailer });
const modals = document.createElement("div");
modals.classList.add("modal");
modals.innerHTML = ` <a target="_blank" href ="https://www.youtube.com/watch?v=${trailer}">Watch Trailer</a>`;
});
}

properly using async and await

The function below calls several asynchronous functions in a for loop. It's parsing different CSV files to build a single JavaScript object. I'd like to return the object after the for loop is done. Its returning the empty object right away while it does the asynchronous tasks. Makes sense, however I have tried various Promise / async /await combinations hopes of running something once the for loop has completed. I am clearly not understanding what is going on. Is there a better pattern to follow for something like this or am I thinking about it incorrectly?
async function createFormConfig(files: string[]): Promise<object>
return new Promise(resolve => {
const retConfig: any = {};
for (const file of files) {
file.match(matchFilesForFormConfigMap.get('FIELD')) ?
parseCsv(file).then(parsedData => {
retConfig.fields = parsedData.data;
})
: file.match(matchFilesForFormConfigMap.get('FORM'))
? parseCsv(file).then(parsedData => retConfig.formProperties = parsedData.data[0])
: file.match(matchFilesForFormConfigMap.get('PDF'))
? parseCsv(file).then(parsedData => retConfig.jsPdfProperties = parsedData.data[0])
: file.match(matchFilesForFormConfigMap.get('META'))
? parseCsv(file).then(parsedData => {
retConfig.name = parsedData.data[0].name;
retConfig.imgType = parsedData.data[0].imgType;
// console.log(retConfig); <- THIS CONSOLE WILL OUTPUT RETCONFIG LOOKING LIKE I WANT IT
})
: file.match(matchFilesForFormConfigMap.get('PAGES'))
? parseCsv(file).then(parsedData => retConfig.pages = parsedData.data)
: console.log('there is an extra file: ' + file);
}
resolve(retConfig); // <- THIS RETURNS: {}
});
This is the code I'm using to call the function in hopes of getting my 'retConfig' filled with the CSV data.
getFilesFromDirectory(`${clOptions.directory}/**/*.csv`)
.then(async (files) => {
const config = await createFormConfig(files);
console.log(config);
})
.catch(err => console.error(err));
};
First, an async function returns a Promise, so you dont have to return one explicitely.Here is how you can simplify your code:
async function createFormConfig(files: string[]): Promise<object> {
// return new Promise(resolve => { <-- remove
const retConfig: any = {};
// ...
// The value returned by an async function is the one you get
// in the callback passed to the function `.then`
return retConfig;
// }); <-- remove
}
Then, your function createFormConfig returns the config before it has finished to compute it. Here is how you can have it computed before returning it:
async function createFormConfig(files: string[]): Promise<object> {
const retConfig: any = {};
// Return a Promise for each file that have to be parsed
const parsingCsv = files.map(async file => {
if (file.match(matchFilesForFormConfigMap.get('FIELD'))) {
const { data } = await parseCsv(file);
retConfig.fields = data;
} else if (file.match(matchFilesForFormConfigMap.get('FORM'))) {
const { data } = await parseCsv(file);
retConfig.formProperties = data[0];
} else if (file.match(matchFilesForFormConfigMap.get('PDF'))) {
const { data } = await parseCsv(file);
retConfig.jsPdfProperties = data[0];
} else if (file.match(matchFilesForFormConfigMap.get('META'))) {
const { data } = await parseCsv(file);
retConfig.name = data[0].name;
retConfig.imgType = data[0].imgType;
} else if (file.match(matchFilesForFormConfigMap.get('PAGES'))) {
const { data } = await parseCsv(file);
retConfig.pages = data;
} else {
console.log('there is an extra file: ' + file);
}
});
// Wait for the Promises to resolve
await Promise.all(parsingCsv)
return retConfig;
}
async functions already return promises, you don't need to wrap the code in a new one. Just return a value from the function and the caller will receive a promise that resolves to the returned value.
Also, you have made an async function, but you're not actually using await anywhere. So the for loop runs through the whole loop before any of your promises resolve. This is why none of the data is making it into your object.
It will really simplify your code to only use await and get rid of the then() calls. For example you can do this:
async function createFormConfig(files: string[]): Promise<object> {
const retConfig: any = {};
for (const file of files) {
if (file.match(matchFilesForFormConfigMap.get('FIELD')){
// no need for the then here
let parsedData = await parseCsv(file)
retConfig.field = parsedData.data
}
// ...etc
At the end you can just return the value:
return retConfig

Save Async/Await response on a variable

I am trying to understand async calls using async/await and try/catch.
In the example below, how can I save my successful response to a variable that can be utilized throughout the rest of the code?
const axios = require('axios');
const users = 'http://localhost:3000/users';
const asyncExample = async () =>{
try {
const data = await axios(users);
console.log(data); //200
}
catch (err) {
console.log(err);
}
};
//Save response on a variable
const globalData = asyncExample();
console.log(globalData) //Promise { <pending> }
1) Return something from your asyncExample function
const asyncExample = async () => {
const result = await axios(users)
return result
}
2) Call that function and handle its returned Promise:
;(async () => {
const users = await asyncExample()
console.log(users)
})()
Here's why should you handle it like this:
You can't do top-level await (there's a proposal for it though);
await must exist within an async function.
However I must point out that your original example doesn't need async/await
at all; Since axios already returns a Promise you can simply do:
const asyncExample = () => {
return axios(users)
}
const users = await asyncExample()
try..catch creates a new block scope. Use let to define data before try..catch instead of const, return data from asyncExample function call
(async() => {
const users = 123;
const asyncExample = async() => {
let data;
try {
data = await Promise.resolve(users);
} catch (err) {
console.log(err);
}
return data;
};
//Save response on a variable
const globalData = await asyncExample();
console.log(globalData);
// return globalData;
})();
I had same issue with you and found this post. After 2 days of trying I finally found a simple solution.
According to the document of JS, an async function will only return a Promise object instead of value. To access the response of Promise, you have to use .then()method or await which can return the resulting object of Promise is instead of Promise itself.
To change variables from await, you have access and change the variable you want to assign within the async function instead of return from it.
//Save response on a variable
var globalData;
const asyncExample = async () =>{
try {
const data = await axios(users);
globalData = data; // this will change globalData
console.log(data); //200
}
catch (err) {
console.log(err);
}
};
asyncExample();
But if you do this, you may get an undefined output.
asyncExample();
console.log(globalData) //undefined
Since asyncExample() is an async function, when console.log is called, asyncExample() has not finished yet, so globalData is still not assigned. The following code will call console.log after asyncExample() was done.
const show = async () => {
await asyncExample();
console.log(globalData);
}
show();
Because the events are happening asynchronously you need to tie in a callback/promise. I'm going to assume it returns a promise.
const axios = require('axios');
const users = 'http://localhost:3000/users';
const asyncExample = async () =>{
try {
const data = await axios(users);
console.log(data); //200
}
catch (err) {
console.log(err);
}
};
//Save response on a variable
const globalData = asyncExample().then( (success, err) => {
if (err) { console.error(err); }
console.log(success)
}
Just use a callback/promise (cascading programming):
axios(users).then(function(response) {
const globalData = response;
console.log(globalData)
});

Categories

Resources