Use of async/await syntax not making sense [duplicate] - javascript

This question already has answers here:
Why is my asynchronous function returning Promise { <pending> } instead of a value?
(9 answers)
Closed 13 days ago.
Im trying to learn async/await syntax and just not making any progress. I have a snippet below that so far returns me this to the console. The idea is that if my map doesnt have a particular key in it, that it will make a callout - wait for response - and then continue. Instead, I just get the promise. Any pointers on where Im going wrong would be really appreciated.
// mymap is a global var
async function retrieveDetails(key){
let url = '/myurl);
let res = '';
const response = await fetch(url, {
headers: {
'Content-Type': 'application/json',
'Authorization' : 'Bearer '+accessToken
}
})
.then((response) => {
mymap.put(key, response);
})
}
function getValue(key){
if(!mymap.has(key)){
retrieveDetails(key);
}
return mymap.get(key);
}
let result = getValue('foo'); // should return me a value from mymap.

Just because you use await inside of retrieveDetails doesn't mean that when you call retrieveDetails that it will wait for retrieveDetails to be done (in fact it never will, unless you await or .then it).
getValue needs to be an async function (which implicity returns a Promise), or return a Promise as a synchronous function, to be able to resolve to the value you want.
With Promises,
function getValue(key){
if(!mymap.has(key)){
return retrieveDetails(key).then(() => mymap.get(key));
}
return Promise.resolve(mymap.get(key));
}
With async
async function getValue(key){
if(!mymap.has(key)){
await retrieveDetails(key);
}
return mymap.get(key);
}
Either way, you need to change how you receive the data:
let result = await getValue('foo');
// or
getValue('foo').then((result) => {
// rest of code
});

Related

Javascript Promise handler called before beeing resolved

In an effort to remove the use of jQuery from my code, I tried to replace the $.Deferred(); by new Promise().
I noticed the usage are slightly different, and I'm still learning how it works.
Here is a simplified extract from my code:
function do_match (resolve, reject) {
fetch( /* ... */).then (async function(response) {
/* do some suff */
document.getElementById("match").insertAdjacentHTML('beforeend', '<div class="player"></div>');
resolve("done");
});
}
function do_myMarket () {
var elements = document.querySelectorAll('.player');
//here elements is sometimes null...
}
p1 = new Promise(do_match);
p1.then(do_myMarket, null);
While I would have expect do_myMarket to only be called after the promise is resolved, if the fetch is not fast enough, do_myMarket can be called before the elements are available in the page.
Putting breakpoints if elements is null and resolve() confirmed me this behavior.
Am I missing something? Why would this happen?
After some readings from #VLAZ and more testing, I found out it's because of the async in the unnamed function.
The promise p1 was resolved by the return value of the fetch function, which would not wait for completion because of the async keyword, thus making resolve("done"); useless.
And I tried, same behavior with or without the call to resolve.
This comes from, what I think now, as a wacky example from MDN:
// Function to do an Ajax call
const doAjax = async () => {
const response = await fetch('Ajax.php'); // Generate the Response object
if (response.ok) {
const jVal = await response.json(); // Get JSON value from the response body
return Promise.resolve(jVal);
}
else
return Promise.reject('*** PHP file not found');
}
}
// Call the function and output value or error message to console
doAjax().then(console.log).catch(console.log);
The above is all antipattern if I understood correctly.
The correct way is the page dedicated to the .json() method:
function doAjax() {
fetch(/* ... */)
.then(response => response.json())
.then(data => {
//...
})
.catch(console.error);
}

how do I store a global variable from a javascript ajax function which returns a promise [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 2 years ago.
I am trying to load an array of memberdata into a javascript variable so that I can operate on it from within several different functions. After giving it the old college try, I am lost.
I understand the need for asynchronous functions so as not to block the main thread but the only way I have been able to populate a global variable is by storing the function result to session.Storage and then calling it from there in other functions. While this works it seems like an extra step.
async function fetchMember($vid) {
let options = {
method: 'POST',
async:false,
body: JSON.stringify({vid: $vid}),
headers: {
'Content-Type': 'application/json', // sent request
'Accept': 'application/json' // expected data sent back
},
}
let response = await fetch('getMember.php', options);
let $member = await response.text();
sessionStorage.setItem("member", $member)
return ($member); // this is a promise because it is in an async function
} //end of function
fetchMember("999999").then ($dog=> console.log ("Then = " + $dog))// $dog is a promise
console.log ("Member = " + $member); // undefined
$member = session.Storage ("member") // work as expected
I can ".then" log the result of the promise to the console but for the life of me I can't figure out how to store it in a global variable.
As mentioned by #epascarello you are not returning your promise from the then block. A simple (maybe hacky) solution could be to wrap your program in an async function then await the response from your fetchMember function. I made a simple jsFiddle with this in practice.
It is not perfect but it should help you get where you need to go!
JsFiddle: https://jsfiddle.net/3q98gx2t/
(async () => {
// Get the data out of the fetchMember function
// It is in the scope of the overall self executing function.
let test = await fetchMember();
async function fetchMember($vid) {
let options = {
method: 'GET',
}
let response = await fetch('https://api.coindesk.com/v1/bpi/currentprice.json', options);
let $member = await response.text();
return $member; // this is a promise because it is in an async function
} //end of function
console.log("Member = " + test); // undefined
})();
The problem with the whole then/catch system is that it will always return a promise so, depending on your project, you will end up in a long ass chain of .then(data => something).then(data => something).
For this example I have used a GET request to the Bitcoin API but the principle remains. Just swap your options back in and it should work.
As you can see I have removed the session storage call.

Using variable from a Async function [duplicate]

This question already has answers here:
Using async/await with a forEach loop
(33 answers)
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 2 years ago.
I have an item that I got from an Async function as follows:
items = await statusCheck(items.split('\n'))
The items is an array which I need to add to localStorage. The issue is, although it has elements inside of it, they are not accessible.
Therefore, I have to do this:
items = await statusCheck(items.split('\n'))
setTimeout(() => {
localStorage.setItem(localKey, items.join('\n'))
}, 1000)
Is there a more elegant way of doing this without having to resort to a setTimeout function?
Is there more information I can provide to help resolve this issue? The FULL code is as follows:
async function clearHistory() {
var localKey = "uploadcare_" + UPLOADCARE_PUBLIC_KEY
var items = localStorage.getItem(localKey);
items = await statusCheck(items.split('\n'))
setTimeout(() => {
localStorage.setItem(localKey, items.join("\n"));
}, 1000)
}
async function statusCheck (items) {
let newItems = []
items.forEach(async (item) => {
let url = "https://somelink" + item.split(' ')[0] + "/54x54/"
let status = await fetchResponse(url)
if (status === 200) {
newItems.push(item)
}
})
return newItems
}
async function fetchResponse(url) {
try {
let response = await fetch(url)
let status = response.status
return status
} catch (e) {
console.log(e)
}
}
clearHistory()
You shouldn't be doing a forEach with async. You should use map and get each promise out. Then do Promise.all. Something like this:
async function statusCheck (items) {
let promises = items.map(item => {
let url = "https://somelink" + item.split(' ')[0] + "/54x54/";
return fetchResponse(url);
});
await Promise.all(promises);
// figure out which ones to return.
}
Async functions need to return a Promise. Your code runs synchronously. I am not sure why the browser won't tell you. So your statusCheck() function needs to return a Promise object to be awaitable. This also applies to the the forEach loop in the statusCheck. And I think that you cant do the foreach async because the native function wont wait for those callbacks.
See this reference for async function: https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Statements/async_function
There is no reason to use setTimeout. the main problem is that you are using await inside the function you are passing to forEach, and there is no reason for javascript to wait until all of the requests resolve and then returning the array. it keeps going and returns possibly an empty array first. and when you are using the new created array it, some of the requests might resolve and they results will be pushed to that array. you can use this instead:
async function statusCheck (items) {
return Promise.all(items.map(async (item) => {
let url = "https://somelink" + item.split(' ')[0] + "/54x54/"
let status = await fetchResponse(URL)
if(status !== 200) {
return;
}
return item;
}).filter(Boolean);
}
I used Boolean just to remove items that checking them by API might result in a status other than 200. in this case the function return;s or in the other words, returns undefined. as a matter of fact, I've filtered those results by filter(Boolean)

JS 'await is only valid in async function' in Promise.all() function [duplicate]

This question already has answers here:
Why is my asynchronous function returning Promise { <pending> } instead of a value?
(9 answers)
Closed 3 years ago.
I'm trying to make a bunch of request an await to all of them to be completed with a Promise.all() function, but instead of doing manually all the fetchs like this:
var data = await Promise.all([
fetch('https://jsonplaceholder.typicode.com/posts').then((response) => response.json()),
fetch('https://jsonplaceholder.typicode.com/albums').then((response) => response.json()),
fetch('https://jsonplaceholder.typicode.com/users').then((response) => response.json())
]);
i want to make it dynamic, to make N fetch requests like this:
let promiseList = [];
try {
for (let url of requestUrls) {
promiseList.push(fetch(url).then((response) => response.json()));
}
var data = await Promise.all(promiseList);
But i get this error Uncaught SyntaxError: await is only valid in async function in the await Promise.all() line, if i delete the await, i get a PromiseĀ {<pending>} and
(index):79 error:TypeError: data is not iterable
This is my full code: https://jsfiddle.net/ham7g82e/1/
What i'm missing to get the data from those fetchs?
Don't use await, instead use Promise.then
Promise.all(promiseList).then(data => {
document.getElementById("result").innerHTML = data;
console.log(data);
for (var i of data) {
console.log(`RESPONSE ITEM \n`);
for (var obj of i) {
console.log(obj);
}
}
});
To use await, it needs to be part of an async function.
async function functionName() {
//You can use await in here, because you used the async keyword
}
If the function where are executing this code is not async, you could just use the .then() to get the values from the promises. There is not need to use await.
Check this documentation: Promise.all()

Promise returning undefined and status pending

I'm adding some functions to an Angular App and here is the thing: I'm trying to use a function that creates a promise to get data from the server, but every time I try to use it, it returns undefined. I've "debugged" with console.log printing my variable with the result of my function as value and it prints Promise{'pending'}
Here is the function of the promise and the variable I'm trying to assign.
all_allies(text = ''){
return new Promise((resolve, reject) => {
const _text = text ? /${text} : ''
const path = `${this.env.apiPath}/all_allies${_text}`
this.$http
.get(path)
.then(response => {
const { data } = response
resolve(data)
return data;
})
.catch(error => reject(error))
})
Variable
let allies = this.AliadosFactory.all_allies();
As you can see the function and the variable are in different scripts.
I've tried using await reserved word but still doesn't work
Can you try this method?
let allies = await this.AliadosFactory.all_allies();
console.log(allies);
or like this?
this.AliadosFactory.all_allies().then(allies => console.log(allies);
I sure it should work,
Hope this helps.
Have nice day :)
That's because when you perform assignment the Promise is not resolved / rejected yet.
There are two simple solutions:
1. Using then()
this.AliadosFactory.all_allies().then(result => console.log(result));
2. Using async/await
(note that you need an async method in your class)
async foo() {
let allies = await this.AliadosFactory.all_allies();
console.log(allies);
}
Also in all_allies() you don't need to return the value after calling the resolve() method;

Categories

Resources