This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 4 years ago.
Im a bit struggling to grasp promises, I have a use case when I perform X async actions, and when these are completed I make call to rest api. below my code:
const promises = defect.images.map(async image => {
return new Promise((resolve)=> {
this.fileProvider.getDefectImage(image.url)
.then(binary => {
images.set(image.url, binary);
resolve();
});
})
});
console.log(images)
return Promise.all(promises)
.then(() => spinner.dismiss())
but the console.log of images is always empty ... what should i change?
//edit
sorry guys for leading into a trap, indeed this console.log can not work properly but Im not getting the data on bakcend side, its also empty there.
You are logging images before any of the promises have been resolved, so it's still empty at that point.
You need to wait for all the promises to be resolved first. And apparently you already know how to do that:
return Promise.all(promises)
.then(() => {
console.log(images);
spinner.dismiss();
})
Besides, you are mixing async/await syntax and Promise syntax. If you're going to rely on async/await, you might as well go all the way, and then your code will be executed from top to bottom again:
const promises = defect.images.map(async image => {
let binary = await this.fileProvider.getDefectImage(image.url);
images.set(image.url, binary);
});
await Promise.all(promises);
console.log(images);
spinner.dismiss();
Related
This question already has answers here:
How to return many Promises and wait for them all before doing other stuff
(6 answers)
Using async/await with a forEach loop
(33 answers)
Closed 1 year ago.
The community reviewed whether to reopen this question 1 year ago and left it closed:
Original close reason(s) were not resolved
Okay, so I have this function that is a simple Axios request. We know that Axios will run as a promise based request so we do something like this and push all the responses into an array
let array = []
function A() {
return axios.get(url).then(r => r.data).then(r => array.push(r.forms))
}
The issue is now I need to call this function specifically 898 times.
async function main() {
await someArrayWithALotOfObjects.forEach(async (e) => {
return await A(e.url);
});
console.log(array);
}
The issue is when I run main() it console logs [], however when I change the main function to be completely hardcoded it outputs all the data correctly pushed to the array in a workable format.
async function main() {
await A(someArrayWithALotOfObjects[0].url);
await A(someArrayWithALotOfObjects[1].url);
await A(someArrayWithALotOfObjects[2].url);
await A(someArrayWithALotOfObjects[3].url);
await A(someArrayWithALotOfObjects[4].url);
await A(someArrayWithALotOfObjects[5].url);
await A(someArrayWithALotOfObjects[6].url);
await A(someArrayWithALotOfObjects[7].url);
...
console.log(array);
}
So my question is how to not hardcode because the loop does not seem to be completed before I run the console.log function.
Note: eventually I will be changing the console logging to the fs event for writing to a file if this helps in writing a better solution.
Note2: IDK how to use the new yield stuff in JavaScript yet, so if that is the solution needed forgive me.
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 1 year ago.
This question may have been asked here before, and I'm sorry, but I wasn't able to find a solution to my problem anywhere. I am relatively new to JavaScript and things like "promises" are alien to me. I am trying to make a code that will load an array from a .JSON file, and after it loads, the code will continue.
async function fetchTags() {
var response = await fetch('../json/tags.json');
var json = await response.json();
console.log(json); // returns: Array()
return json;
}
function mainFunction() {
let tags = fetchTags();
console.log(tags); // returns: Promise { <state>: "pending" }
}
This is what my current code looks like, using a not-working "solution" I found on the internet. While the console.log(json), which is inside of the async function, returns the array correctly, the main function's console.log(tags) displays this promise with a "pending" state - and displays sooner than the array can be loaded, if I understand correctly.
The following code of the mainFunction() however relies strongly on this array, and it should not proceed before the array is loaded. Where am I making a mistake?
Thanks a lot for all your replies.
At this point, fetchTags is an asynchronous function and needs to be treated as such when calling it. You have two implementation options here:
Use async/await for your mainFunction function:
async function mainFunction() {
let tags = await fetchTags()
console.log(tags)
}
Appropriately handle the promise that is returned by the function:
function mainFunction() {
fetchTags()
.then(console.log)
.catch(console.error)
}
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 2 years ago.
I am getting into Node, and being thrown into the world of async programming.
I thoroughly read this article on Mozilla's site (along with many other links teaching about the async and await keywords):
https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await
I have a project I am starting that will require numerous database calls, one after another. Some queries will rely upon the previous one's results. That being said, I decided I better practice and write some testing code.
Here is my testing code:
var users, items;
const getData = async function(){
// This is a DB call. Will take
// a little bit of time to complete.
setTimeout(() => {
var queryResults = "A list of items";
items = queryResults;
}, 1000);
return items;
}
const getUsers = async function(){
setTimeout(() => {
var queryResults = "A list of items";
users = queryResults;
}, 1000);
return users;
}
const init = async function(){
var itemSuccess = await getData();
var userSuccess = await getUsers();
console.log(`Here is your items: ${items}, and here are your users: ${users}`);
}
init();
My code failed with:
Here is your items: undefined, and here are your users: undefined
So naturally I headed back to Mozilla. I re-read the docs, and tried a few changes. Still, no success. Ultimately I ended up back at my original code above.
I cannot see why this is failing. I am simulating the time a query would take by using a timeout. If async does what it says, both functions should return their value, and then my console log should print out the correct results.
Does anyone see where I am going wrong?
Thank you.
Show us your REAL code with the actual database calls in it and we can help you much more specifically, including showing you working code. Please resist the temptation to post questions with pseudo-code. Show real code and we can help you so much faster and better if you show us the real code.
await ONLY does something useful when you await a promise that resolves or rejects when something you are interested in completes or errors.
It has no magic to somehow know when a a setTimeout() or any other asynchronous operation is done doing whatever it does.
So, when you do this:
var itemSuccess = await getData();
And, getData() looks like this:
const getData = async function(){
// This is a DB call. Will take
// a little bit of time to complete.
setTimeout(() => {
var queryResults = "A list of items";
items = queryResults;
}, 1000);
return items;
}
All you end up doing is:
var itemSuccess = await undefined
because your getData() function doesn't return a promise and, in fact, it doesn't even return the items because it returns BEFORE your timer so items (which doesn't appear to be declared properly here) has not yet received its value.
So, I would suggest you start back with the basics and go read what await really does. Make sure you understand how it interacts with a promise since it's only useful when used with a promise. And, then learn how to make your asynchronous operations return promises that are connected to when your asynchronous operations complete. Then, and only then, can you make proper use of await.
In a well organized world, you make sure that all your asynchronous operations are already returned promises and then you can async/await and .then() and .catch() to control the flow of all your asynchronous operations. In many cases, this involves learning the promise interface for whatever you're using. For example, modern versions of node.js have an entire promise interface for the file system in fs.promises.
In a few cases, there may not exist a promise interface for some library you're using and you may have to wrap the asynchronous operation in a promise to make your own promise interface. util.promisify() is built-into node.js to help you do that.
If you show the ACTUAL code, include which database you're using and the actual database call you're trying to make, then someone here can probably help you with the proper way to use the promise interface on the database. This pseudo code prevents us from helping you that specifically. Without your actual code and knowing the actual DB calls you're making in a specific DB, it's hard for us to advise much more than go use the promise interface to your database and learn how to use those promises properly. Happy to help more specifically, but we need to see you REAL code to do that.
And, lastly in Javascript if you're assigning a value to something in a higher scope from within any asynchronous callback, there's a 99.99% chance you're doing things wrong. The only place you can actually use that value is inside the callback itself or in a function that you call from there and pass the value to. So, when you do items = queryResults, where items is declared in a couple scopes above you, then alarm bells should go off that this is not going to work for you. It's not how you program with asynchronous code in Javascript, not just for style reasons, but because it doesn't work.
Use:
function timeout(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
instead of
setTimeout(() => {
}, 1000);
await waits for a Promise to resolve.
// normal function that returns a promise
const getData = function(){
// This is a DB call. Will take
// a little bit of time to complete.
return new Promise(resolve => {
setTimeout(() => {
var queryResults = "A list of data";
resolve(queryResults);
}, 1000);
});
}
const getUsers = function(){
return new Promise(resolve => {
setTimeout(() => {
var queryResults = "A list of users";
resolve(queryResults);
}, 1000);
});
}
const init = async function(){
var itemSuccess = await getData();
var userSuccess = await getUsers();
console.log(`Here is your items: ${itemSuccess}, and here are your users: ${userSuccess}`);
}
init();
An async function does 2 things.
it makes it possible to use the await keyword to wait for promises.
it makes the function automatically return a promise itself that wraps whatever the function returns
async function foo() {
return 123;
}
const v = foo();
console.log(v instanceof Promise);
v.then(value => console.log(value));
A more normal database query might look something like this
async function dbQuery(queryUrl) {
const res = await fetch(queryUrl); // fetch returns a promise that resolves to a Response
return res.json(); // res.json returns a promise that resolves to the body of response parsed as json.
}
async function main() {
const films = await dbQuery('https://greggman.github.io/doodles/test/data/films.json');
console.log(JSON.stringify(result, null, 2));
}
main();
This question already has answers here:
Correct way to write loops for promise.
(13 answers)
Closed 4 years ago.
I have a PHP script which does a loop (several thousand times). Each loop requests a paginated URL which returns some results in JSON. Each result requires at least 2 further API hits to request more information. Once all this is complete, I'd build this into a packet for indexing/storing.
In PHP this is quite easy as it's naturally synchronous.
I'm in the process of moving this to a NodeJS setup and finding it difficult to elegantly do this in NodeJS.
If I make a for-loop, the initial HTTP request (which is often promise based) would complete almost instantly, leaving the resolution of the request to the promise handlers. This means all several-thousand page requests would end up being fired pretty much in parallel. It would also mean I'd have to chain up the sub-requests within the promise resolution (which leads to further promise chains as I have to wait for those to be resolves).
I've tried using the async/await approach, but they dont seem to play nicely with for-loops (or forEach, at least).
This is roughly what I'm working with right now, but I'm starting to think its entirely wrong and I could be using callbacks to trigger the next loop?!
async processResult(result) {
const packet = {
id: result.id,
title: result.title,
};
const subResponse1 = await getSubThing1();
packet.thing1 = subResponse1.body.thing1;
const subResponse2 = await getSubThing2();
packet.thing2 = subResponse2.body.thing2;
}
(async () => {
for (let page = START_PAGE; page < MAX_PAGES; page += 1) {
console.log(`Processing page ${page}...`);
getList(page)
.then(response => Promise.all(response.body.list.map(processResult)))
.then(data => console.log('DATA DONE', data));
console.log(`Page ${page} done!`);
}
})();
I've tried using the async/await approach, but they dont seem to play nicely with for-loops (or forEach, at least).
Yes, async/await does not play nicely with forEach. Do not use forEach! But putting an await in your normal for loop will work just fine:
(async () => {
for (let page = START_PAGE; page < MAX_PAGES; page += 1) {
console.log(`Processing page ${page}...`);
const response = await getList(page);
const data = await Promise.all(response.body.list.map(processResult));
console.log('DATA DONE', data);
console.log(`Page ${page} done!`);
}
})();
This question already has answers here:
How to "await" for a callback to return?
(5 answers)
Closed 5 years ago.
I've got the following code block:
new Promise((res, rej) => {
if (checkCondition()) {
res(getValue())
} else {
getValueAsync((result) => {
res(result)
})
}
}).then((value) => {
doStuff(value)
})
I'd like to convert this to use async/await, but I can't figure out how to do it. I know when you're working exclusively with promises, you replace the calls to then() with value = await ..., but How do I make this work with callbacks? Is it possible?
First of all, you have to make sure you are in an async function to begin with. Then it could be something along the lines of:
async function example() {
let value = (checkCondition() ? getValue() : await getValueAsync());
doStuff(value);
}
await example();
This, however, assumes that you can modify getValueAsync as well, to make it an async function or to make it return a Promise. Assuming getValueAsync has to take a callback, there is not that much we can do:
async function example() {
let value = (checkCondition()
? getValue()
: await new Promise(res => getValueAsync(res))
);
doStuff(value);
}
await example();
You still gain the benefit of not having to create the full Promise chain yourself. But, getValueAsync needs to be wrapped in a Promise in order to be usable with await. You should carefully consider whether this kind of a change is worth it for you. E.g. if you are in control of most of the codebase and / or most of the functions you are calling are already async / return Promises.