I have dynamic components that needs to be validated.
I have an array and i push my components there. The for loop works great.
validateForm() {
const PROMISES = [this.$refs.contactDetailsForm.$refs.contactDetails]
for (let i = 1; i <= this.count; i++) {
PROMISES.push(this.$refs[`passengerForm${i}`][0])
}
return Promise.all(PROMISES)
},
But problem is I do not know how to return the results of the validation. I want the results of this function in another function(Promise). how can I do that?
this is the solution:
validateForm() {
const PROMISES = [this.$refs.contactDetailsForm.$refs.contactDetails]
for (let i = 1; i <= this.count; i++) {
PROMISES.push(this.$refs[`passengerForm${i}`][0])
}
return new Promise((resolve, reject) => {
PROMISES.forEach(async (item) => {
const STATUS = await item.validate()
STATUS ? resolve(STATUS) : reject(STATUS)
})
})
}
Untested, but Promise.all returns an array of results for the promises. What you need to do is trigger validate for all the things you want to know the result for, collect those promises and then check the results in a Promise.all. You didn't give quite enough code to answer this fully but it's something like this:
validateForm() {
//both of these I added validate() to because I'm hoping they are references to ValidationObservers
const PROMISES = [this.$refs.contactDetailsForm.$refs.contactDetails.validate()]
for (let i = 1; i <= this.count; i++) {
PROMISES.push(this.$refs[`passengerForm${i}`][0].validate())
}
return Promise.all(Promises);
}
Then wherever you are calling this, you'd do:
this.validateForm().then((values) => {
this.formIsValid = values.every((result) => result));
//if the things above are ValidationProviders rather than VO, you have to use result.valid instead of result
});
Related
I collect the information of each page from 1 to 10 as API in node.js.
Now I use this code.
async function myWork() {
let results = []
let tmp
let param
for (i=1; i<11; i++) {
param = {'page': i}
tmp = await callMyApi(param) // return a list
results.push(...tmp)
}
return results
}
In this case, each callMyApi behaves like sync.
But I don't care about page order.
So, to speed it up, I want to use something like promise.all to process it in parallel.
How can I use promise.all in for loop in this case?
You can use Promise.all() with concat().
async function myWork() {
let results = [];
let promises = [];
let param;
for (i=1; i<11; i++) {
let param = {'page': i}
let tmpPromise = callMyApi(param);
promises .push(tmpPromise);
}
//promises is now an array of promises, and can be used as a param in Promise.all()
let resolved = await Promise.all(promises);
//resolved is an array of resolved promises, each with value returned by async call
let indivResult = resolved.forEach(a =>
results = results.concat(a));
//for each item in resolved array, push them into the final results using foreach, you can use different looping constructs here but forEach works too
return results;
}
Example below:
async function myWork() {
let results = [];
let param;
for (i = 1; i < 11; i++) {
param = { page: i };
results.push(callMyApi(param));
}
const res = await Promise.all(results);
return res.flat();
}
i have one question! I want the function getMealSummary() to return after the for loop has finished already finished (I didnt include the return key because the function is very big and i just had a doubt in this section).
How can I do it with async/await or promises?
Thanks
export const getMealMicroSummaryHelper = async function getMealSummary(array, populatedFoods, customMeasurements, isRecipe,expertId){
var [totalZinc, totalCalcium,totalAlphaCarotene,totalBetaCarotene,totalCholine,totalCopper,totalBetaCrypto,totalFluoride,totalVitaminB9,totalIron,
totalLutein,totalLycopene,totalMagnesium,totalManganese,totalNiacin,totalVitaminB5,totalPhosphorus,totalPotassium,totalRetinol,totalRiboflavin,
totalSelenium,totalSodium,totalTheobromine,totalVitaminA,totalVitaminB12,totalVitaminB6,totalVitaminC,totalVitaminD,totalVitaminD2,totalVitaminD3,
totalVitaminE,totalThiamin] = [0, 0, 0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
let recipesArray = []
for(let i = 0; i < populatedFoods.length; i++){
if(populatedFoods[i].foodType === 4){
await apiCall("get",`/api/experts/${expertId}/recipes/${populatedFoods[i]._id}`)
.then(recipe =>{
recipesArray.push(recipe)
})
.catch((err)=>console.log(err))
}
You can use a combination of map() and Promise.all for this like:
async function getMealSummary(array, populatedFoods, customMeasurements, isRecipe, expertId) {
try {
let recipesArray = await Promise.all(
populatedFoods.map(async populatedFoods => {
if (populatedFoods[i].foodType === 4) {
let recipe = await apiCall("get", `/api/experts/${expertId}/recipes/${populatedFoods[i]._id}`)
return recipe;
}
})
)
} catch (err) {
console.log(err)
}
}
This is just a simple version to give you a basic idea. I have not included all the variables that you have declared above recipesArray. Those will need to be included as needed.
var a = ['url1', 'url2', 'url3'];
var op = [];
cb = (callback) => {
for (var i = 0; i < a.length; i++) {
gtts.savetos3(`${a[i]}.mp3`, a[i], 'ta', function(url) {
console.log(url['Location']);
op.push(url['Location']);
});
}
callback()
}
cb(() => {
console.log(op);
})
In the above code the gtts.savetos3 is an asynchronous function.It takes significance amount of time to complete the execution for every element in array.Due to asynchronous feature I cannot print the complete array of url in op array as it prints an empty array.
gtts.savetos3 function calls the given callback with correct url so that i can print the output using console.log but when comes to looping i got messed up.
My question is
How to make the callback function called only after the execution of
the all array elements get processed by the gtts.savetos3 function.
can we achieve the solution for above problem without Promise.all or without Promise with the help of using only callbacks.
Thanks in Advance ...!
You can keep a counter and increase it inside the methods's callback,
call your done callback only when the counter reaches the length of
the array.
cb = (done) => {
let counter = 0;
for (let i = 0; i < a.length; i++) {
gtts.savetos3(`${a[i]}.mp3`, a[i], 'ta', function (url) {
console.log(url['Location']);
op.push(url['Location']);
++counter;
if (counter == a.length) {
done();
}
});
}
}
cb(() => {
console.log(op);
})
This is just a way to solve the problem without Promises or any third party module but not the elegant or correct way.
If you want to stick to the callback and are ok to use third-party module have a look on
Async waterfall method.
If you are using aws-sdk's s3 put object, then sdk already provides a
promisified methods as well, you can simply append your method with
.promise to get the same.
To solve the problem with promises just change your wrapper into an
async function.
async savetos3(...parametres) {
//Some implementation
let res = await S3.putObject(....params).promise();
//Some implementation
}
cb = Promise.all(a.map(name => savetos3(`${name}.mp3`, name , 'ta')));
cb.then(() => {
console.log(op);
})
Here is my solution.
const a = ['url1', 'url2', 'url3'];
const op = [];
const saveToS3 = name => new Promise((resolve, reject) => {
gtts.savetos3(`${name}.mp3`, name, 'ta', function (url) {
console.log(url['Location']);
resolve(url)
});
})
Promise.all(a.map(item => saveToS3(item))).then(() => {
console.log(op)
})
I am new to Nodejs and first time working on promises so now the context is when I try to return promise it shows status Promise . How to fix it can anyone guide me through this?
Here is the code where I am calling a function that will return a promise. bold line showing where I want to return that promise and store in an object.
for(let i = 0; i<responseArray.length; i++){
let dollar = {
amount : 0
};
if(i == 1){
continue;
}
dollar.amount = **currenciesService.getCurrencyLatestInfo(responseArray[i].currency);**
dollarAmount.push(dollar);
}
console.log("$", dollarAmount);
Here is a code which is returning promise.
const getCurrencyLatestInfo = function(currency) {
return new Promise(function(resolve, reject) {
request('https://min-api.cryptocompare.com/data/price?fsym='+currency+'&tsyms='+currency+',USD', { json: true }, (err, res, body) =>
{
if (err) {
reject(err);
} else {
var result= body;
resolve(result);
console.log("RESULT: ",result.USD);
}
});
})
}
You'll need to wait for those promises to resolve before you can use the resolved values
here is a small rewrite of your loop that should work
let promises = [];
for(let i = 0; i<responseArray.length; i++){
if(i == 1){
continue;
}
let dollar = currenciesService.getCurrencyLatestInfo(responseArray[i].currency)
.then(amount => ({amount})); // do you really want this?
promises.push(dollar);
}
Promise.all(promises)
.then(dollarAmount =>console.log("$", dollarAmount))
.catch(err => console.error(err));
This should result in an array like [{amount:123},{amount:234}] as your code seems to expect
The above can also be simplified to
Promise.all(
responseArray
.filter((_, index) => index != 1)
.map(({currency}) =>
currenciesService.getCurrencyLatestInfo(currency)
.then(amount => ({amount})) // do you really want this?
)
)
.then(dollarAmount =>console.log("$", dollarAmount))
.catch(err => console.error(err));
Note: your original code suggests you want the results to be in the form {amount:12345} - which seems odd when you want to console.log("$", ....) ... because the console output would be something like
$ [ { amount: 1 }, { amount: 0.7782 } ]
given two results of course - can't see your responseArray so, am only guessing
I am trying to return after all the calls to an external service are done but my code is just flying through the for loop and returning. I cannot do a promise.all here as I need some values obtained in the loop. Is there an easy way to do this in typescript/angular2?
var ret = [];
for (var l in users){
var userLicense = users[l].licenseNumber;
this.callExternalService(userLicense).subscribe(response=>{
ret.push(response+userLicense);
}
}
resolve(ret);
As you are already using observables, you can use a combination of forkJoin and map to achieve this:
var ret = [];
Observable.forkJoin(
users.map(
user => this.callExternalService(user.licenseNumber)
.map(response => response + user.licenseNumber)
)
).subscribe(values => {
ret = values;
resolve(ret);
})
You could try combineLatest:
return Observable.combineLatest(
...users.map(user => this.callExternalService(user.licenseNumber)
.map(response => response + user.licenseNumber)),
(...vals) => vals);
This will return an observable of arrays of results from the service calls, which you can then subscribe to, convert to a promise with toPromise if you prefer, etc.
if you need to do some aggregation in the loop and pass it as part of return, you can add it into a Promise.all as Promise.resolve(aggregatedData)
Something like that:
function getData(ii) {
return new Promise(res => {
res(ii);
});
}
function getUserData(users) {
let promiseArray = [];
let aggregatedData = 0;
users.forEach(user => {
aggregatedData += user.id;
promiseArray.push(getData(user.id));
});
promiseArray.push(Promise.resolve(aggregatedData));
return Promise.all(promiseArray);
}
getUserData([{id:1}, {id:2}, {id:3}]).then(x=>console.log(x))