How to return promise? - javascript

I have a function
parseJobs(userId: string) {
this.getLikedJobs(userId).subscribe(result => {
result.map(key =>{
let rows = {
name : (key as any).jobsUser.firstName,
jobType: 'Liked'
}
let job = {...rows,...(key as any).jobPosting};
this.result.push(job);
});
});
this.getSavedJobs(userId).subscribe(result => {
result.map(key =>{
let rows = {
name : (key as any).jobsUser.firstName,
jobType: 'Saved'
}
let job = {...rows,...(key as any).jobPosting};
this.result.push(job);
});
});
return this.result;
}
How to return the result to promise, I tried my best, But I don't know to do t, Maybe its because of two observable I have inside of it,

You would promisify both observables, and then use Promise.all to get a promise that fulfils when all is done:
parseJobs(userId: string) {
// Create a promise
const p1 = new Promise(resolve => {
this.getLikedJobs(userId).subscribe(result => {
// Resolve with the modified array
resolve(result.map(key =>{
let rows = {
name : (key as any).jobsUser.firstName,
jobType: 'Liked'
}
let job = {...rows,...(key as any).jobPosting};
// In a map, you want to return:
return job;
}));
});
});
// Same here:
const p2 = new Promise(resolve => {
this.getSavedJobs(userId).subscribe(result => {
resolve(result.map(key =>{
let rows = {
name : (key as any).jobsUser.firstName,
jobType: 'Saved'
}
let job = {...rows,...(key as any).jobPosting};
return job;
}));
});
});
// Return a promise that will fulfill when both promises fulfill
// and concatenate the results
return Promise.all([p1, p2]).then(result => [].concat(...result));
}
Now you don't store the result in this.result, but make it the promised value, which you get like this:
parseJobs(1).then(result =>
console.log(result);
});
You could of course still store the result in this.result, but that would not be best practice as it suggests that a piece of code may try to access it before it is available: you would always use the then method to get to the result.

Maybe you need something like that:
parseJobs(userId: string): Promise<any> {
let res: Function;
const resPromise = new Promise((resolve: Function) => {
// passing resolve function to upper scope
res = resolve;
});
this.getLikedJobs(userId).subscribe(result => {
...
// resolving result promise
res(result);
});
...
// unresolved
return resPromise;
}

You have 2 async calls. So there is also a single promise solution based on this knowledge.
parseJobs(userId: string) =>
new Promise(resolve => {
let result = [];
const done = (job) => {
result.push(job);
if(result.length === 2) {
resolve(result);
}
}
this.getLikedJobs(userId).subscribe(result => {
result.map(key =>{
let rows = {
name : (key as any).jobsUser.firstName,
jobType: 'Liked'
}
let job = {...rows,...(key as any).jobPosting};
done(job);
});
});
this.getSavedJobs(userId).subscribe(result => {
result.map(key =>{
let rows = {
name : (key as any).jobsUser.firstName,
jobType: 'Saved'
}
let job = {...rows,...(key as any).jobPosting};
done(job);
});
});
});
Also you may look at Promise.all method.

Related

How can I filter a collection in parallel? [duplicate]

Given
let arr = [1,2,3];
function filter(num) {
return new Promise((res, rej) => {
setTimeout(() => {
if( num === 3 ) {
res(num);
} else {
rej();
}
}, 1);
});
}
function filterNums() {
return Promise.all(arr.filter(filter));
}
filterNums().then(results => {
let l = results.length;
// length should be 1, but is 3
});
The length is 3 because Promises are returned, not values. Is there a way to filter the array with a function that returns a Promise?
Note: For this example, fs.stat has been replaced with setTimeout, see https://github.com/silenceisgolden/learn-esnext/blob/array-filter-async-function/tutorials/array-filter-with-async-function.js for the specific code.
Here is a 2017 elegant solution using async/await :
Very straightforward usage:
const results = await filter(myArray, async num => {
await doAsyncStuff()
return num > 2
})
The helper function (copy this into your web page):
async function filter(arr, callback) {
const fail = Symbol()
return (await Promise.all(arr.map(async item => (await callback(item)) ? item : fail))).filter(i=>i!==fail)
}
Demo:
// Async IIFE
(async function() {
const myArray = [1, 2, 3, 4, 5]
// This is exactly what you'd expect to write
const results = await filter(myArray, async num => {
await doAsyncStuff()
return num > 2
})
console.log(results)
})()
// Arbitrary asynchronous function
function doAsyncStuff() {
return Promise.resolve()
}
// The helper function
async function filter(arr, callback) {
const fail = Symbol()
return (await Promise.all(arr.map(async item => (await callback(item)) ? item : fail))).filter(i=>i!==fail)
}
I'll even throw in a CodePen.
As mentioned in the comments, Array.prototype.filter is synchronous and therefore does not support Promises.
Since you can now (theoretically) subclass built-in types with ES6, you should be able to add your own asynchronous method which wraps the existing filter function:
Note: I've commented out the subclassing, because it's not supported by Babel just yet for Arrays
class AsyncArray /*extends Array*/ {
constructor(arr) {
this.data = arr; // In place of Array subclassing
}
filterAsync(predicate) {
// Take a copy of the array, it might mutate by the time we've finished
const data = Array.from(this.data);
// Transform all the elements into an array of promises using the predicate
// as the promise
return Promise.all(data.map((element, index) => predicate(element, index, data)))
// Use the result of the promises to call the underlying sync filter function
.then(result => {
return data.filter((element, index) => {
return result[index];
});
});
}
}
// Create an instance of your subclass instead
let arr = new AsyncArray([1,2,3,4,5]);
// Pass in your own predicate
arr.filterAsync(async (element) => {
return new Promise(res => {
setTimeout(() => {
res(element > 3);
}, 1);
});
}).then(result => {
console.log(result)
});
Babel REPL Demo
For typescript folk (or es6 just remove type syntax)
function mapAsync<T, U>(array: T[], callbackfn: (value: T, index: number, array: T[]) => Promise<U>): Promise<U[]> {
return Promise.all(array.map(callbackfn));
}
async function filterAsync<T>(array: T[], callbackfn: (value: T, index: number, array: T[]) => Promise<boolean>): Promise<T[]> {
const filterMap = await mapAsync(array, callbackfn);
return array.filter((value, index) => filterMap[index]);
}
es6
function mapAsync(array, callbackfn) {
return Promise.all(array.map(callbackfn));
}
async function filterAsync(array, callbackfn) {
const filterMap = await mapAsync(array, callbackfn);
return array.filter((value, index) => filterMap[index]);
}
es5
function mapAsync(array, callbackfn) {
return Promise.all(array.map(callbackfn));
}
function filterAsync(array, callbackfn) {
return mapAsync(array, callbackfn).then(filterMap => {
return array.filter((value, index) => filterMap[index]);
});
}
edit: demo
function mapAsync(array, callbackfn) {
return Promise.all(array.map(callbackfn));
}
function filterAsync(array, callbackfn) {
return mapAsync(array, callbackfn).then(filterMap => {
return array.filter((value, index) => filterMap[index]);
});
}
var arr = [1, 2, 3, 4];
function isThreeAsync(number) {
return new Promise((res, rej) => {
setTimeout(() => {
res(number === 3);
}, 1);
});
}
mapAsync(arr, isThreeAsync).then(result => {
console.log(result); // [ false, false, true, false ]
});
filterAsync(arr, isThreeAsync).then(result => {
console.log(result); // [ 3 ]
});
Here's a way:
var wait = ms => new Promise(resolve => setTimeout(resolve, ms));
var filter = num => wait(1).then(() => num == 3);
var filterAsync = (array, filter) =>
Promise.all(array.map(entry => filter(entry)))
.then(bits => array.filter(entry => bits.shift()));
filterAsync([1,2,3], filter)
.then(results => console.log(results.length))
.catch(e => console.error(e));
The filterAsync function takes an array and a function that must either return true or false or return a promise that resolves to true or false, what you asked for (almost, I didn't overload promise rejection because I think that's a bad idea). Let me know if you have any questions about it.
var wait = ms => new Promise(resolve => setTimeout(resolve, ms));
var filter = num => wait(1).then(() => num == 3);
var filterAsync = (array, filter) =>
Promise.all(array.map(entry => filter(entry)))
.then(bits => array.filter(entry => bits.shift()));
filterAsync([1,2,3], filter)
.then(results => console.log(results.length))
.catch(e => console.error(e));
var console = { log: msg => div.innerHTML += msg + "<br>",
error: e => console.log(e +", "+ (e.lineNumber-25)) };
<div id="div"></div>
Promise Reducer to the rescue!
[1, 2, 3, 4].reduce((op, n) => {
return op.then(filteredNs => {
return new Promise(resolve => {
setTimeout(() => {
if (n >= 3) {
console.log("Keeping", n);
resolve(filteredNs.concat(n))
} else {
console.log("Dropping", n);
resolve(filteredNs);
}
}, 1000);
});
});
}, Promise.resolve([]))
.then(filteredNs => console.log(filteredNs));
Reducers are awesome. "Reduce my problem to my goal" seems to be a pretty good strategy for anything more complex than what the simple tools will solve for you, i.e. filtering an array of things that aren't all available immediately.
asyncFilter method:
Array.prototype.asyncFilter = async function(f){
var array = this;
var booleans = await Promise.all(array.map(f));
return array.filter((x,i)=>booleans[i])
}
Late to the game but since no one else mentioned it, Bluebird supports Promise.map which is my go-to for filters requiring aysnc processing for the condition,
function filterAsync(arr) {
return Promise.map(arr, num => {
if (num === 3) return num;
})
.filter(num => num !== undefined)
}
Two lines, completely typesafe
export const asyncFilter = async <T>(list: T[], predicate: (t: T) => Promise<boolean>) => {
const resolvedPredicates = await Promise.all(list.map(predicate));
return list.filter((item, idx) => resolvedPredicates[idx]);
};
In case someone is interested in modern typescript solution (with fail symbol used for filtering):
const failSymbol = Symbol();
export async function filterAsync<T>(
itemsToFilter: T[],
filterFunction: (item: T) => Promise<boolean>,
): Promise<T[]> {
const itemsOrFailFlags = await Promise.all(
itemsToFilter.map(async (item) => {
const hasPassed = await filterFunction(item);
return hasPassed ? item : failSymbol;
}),
);
return itemsOrFailFlags.filter(
(itemOrFailFlag) => itemOrFailFlag !== failSymbol,
) as T[];
}
There is a one liner to to do that.
const filterPromise = (values, fn) =>
Promise.all(values.map(fn)).then(booleans => values.filter((_, i) => booleans[i]));
Pass the array into values and the function into fn.
More description on how this one liner works is available here.
For production purposes you probably want to use a lib like lodasync:
import { filterAsync } from 'lodasync'
const result = await filterAsync(async(element) => {
await doSomething()
return element > 3
}, array)
Under the hood, it maps your array by invoking the callback on each element and filters the array using the result. But you should not reinvent the wheel.
You can do something like this...
theArrayYouWantToFilter = await new Promise(async (resolve) => {
const tempArray = [];
theArrayYouWantToFilter.filter(async (element, index) => {
const someAsyncValue = await someAsyncFunction();
if (someAsyncValue) {
tempArray.push(someAsyncValue);
}
if (index === theArrayYouWantToFilter.length - 1) {
resolve(tempArray);
}
});
});
Wrapped within an async function...
async function filter(theArrayYouWantToFilter) {
theArrayYouWantToFilter = await new Promise(async (resolve) => {
const tempArray = [];
theArrayYouWantToFilter.filter(async (element, index) => {
const someAsyncValue = await someAsyncFunction();
if (someAsyncValue) {
tempArray.push(someAsyncValue);
}
if (index === theArrayYouWantToFilter.length - 1) {
resolve(tempArray);
}
});
});
return theArrayYouWantToFilter;
}
A valid way to do this (but it seems too messy):
let arr = [1,2,3];
function filter(num) {
return new Promise((res, rej) => {
setTimeout(() => {
if( num === 3 ) {
res(num);
} else {
rej();
}
}, 1);
});
}
async function check(num) {
try {
await filter(num);
return true;
} catch(err) {
return false;
}
}
(async function() {
for( let num of arr ) {
let res = await check(num);
if(!res) {
let index = arr.indexOf(num);
arr.splice(index, 1);
}
}
})();
Again, seems way too messy.
A variant of #DanRoss's:
async function filterNums(arr) {
return await arr.reduce(async (res, val) => {
res = await res
if (await filter(val)) {
res.push(val)
}
return res
}, Promise.resolve([]))
}
Note that if (as in current case) you don't have to worry about filter() having
side effects that need to be serialized, you can also do:
async function filterNums(arr) {
return await arr.reduce(async (res, val) => {
if (await filter(val)) {
(await res).push(val)
}
return res
}, Promise.resolve([]))
}
Late to the party, and I know that my answer is similar to other already posted answers, but the function I'm going to share is ready for be dropped into any code and be used.
As usual, when you have to do complex operations on arrays, reduce is king:
const filterAsync = (asyncPred) => arr =>
arr.reduce(async (acc,item) => {
const pass = await asyncPred(item);
if(pass) (await acc).push(item);
return acc;
},[]);
It uses modern syntax so make sure your target supports it. To be 100% correct you should use Promise.resolve([]) as the initial value, but JS just doesn't care and this way it is way shorter.
Then you can use it like this:
var wait = ms => new Promise(resolve => setTimeout(resolve, ms));
const isOdd = x => wait(1).then(()=>x%2);
(filterAsync(isOdd)([1,2,3,4,4])).then(console.log) // => [1,3]
Here's a shorter version of #pie6k's Typescript version:
async function filter<T>(arr: T[], callback: (val: T) => Promise<Boolean>) {
const fail = Symbol()
const result = (await Promise.all(arr.map(async item => (await callback(item)) ? item : fail))).filter(i => i !== fail)
return result as T[] // the "fail" entries are all filtered out so this is OK
}
An efficient way of approaching this is by processing arrays as iterables, so you can apply any number of required operations in a single iteration.
The example below uses library iter-ops for that:
import {pipe, filter, toAsync} from 'iter-ops';
const arr = [1, 2, 3]; // synchronous iterable
const i = pipe(
toAsync(arr), // make our iterable asynchronous
filter(async (value, index) => {
// returns Promise<boolean>
})
);
(async function() {
for await (const a of i) {
console.log(a); // print values
}
})();
All operators within the library support asynchronous predicates when inside an asynchronous pipeline (why we use toAsync), and you can add other operators, in the same way.
Use of Promise.all for this is quite inefficient, because you block the entire array from any further processing that can be done concurrently, which the above approach allows.

How to wait for each value of an observable with a promise

Let's say I have this observable:
const obs = new Observable((observer) => {
observer.next(0.25);
observer.next(0.75);
observer.next(new ArrayBuffer(100));
observer.complete();
});
How can I wait for each value with a promise?
The following code will only return the last value (value before complete() is called):
const value = await obs.toPromise();
But I want to be able to get each value along the way. I can do something like this:
const value1 = await obs.pipe(take(1)).toPromise();
const value2 = await obs.pipe(take(2)).toPromise();
But that's not ideal, since I'd have to increment the number each time and also take(1000) would still return something in the example, even though there are only 3 values. I'm looking for something like:
const value1 = await obs.pipe(next()).toPromise(); // 0.25
const value2 = await obs.pipe(next()).toPromise(); // 0.75
const value3 = await obs.pipe(next()).toPromise(); // ArrayBuffer(100)
const value4 = await obs.pipe(next()).toPromise(); // null
That is more akin to a generator.
Is there a way to accomplish something like this?
It seems like what you are asking for is a way to convert an observable into an async iterable so that you can asynchronously iterate over its values, either "by hand" or using the new for-await-of language feature.
Heres' an example of how to do that (I've not tested this code, so it might have some bugs):
// returns an asyncIterator that will iterate over the observable values
function asyncIterator(observable) {
const queue = []; // holds observed values not yet delivered
let complete = false;
let error = undefined;
const promiseCallbacks = [];
function sendNotification() {
// see if caller is waiting on a result
if (promiseCallbacks.length) {
// send them the next value if it exists
if (queue.length) {
const value = queue.shift();
promiseCallbacks.shift()[0]({ value, done: false });
}
// tell them the iteration is complete
else if (complete) {
while (promiseCallbacks.length) {
promiseCallbacks.shift()[0]({ done: true });
}
}
// send them an error
else if (error) {
while (promiseCallbacks.length) {
promiseCallbacks.shift()[1](error);
}
}
}
}
observable.subscribe(
value => {
queue.push(value);
sendNotification();
},
err => {
error = err;
sendNotification();
},
() => {
complete = true;
sendNotification();
});
// return the iterator
return {
next() {
return new Promise((resolve, reject) => {
promiseCallbacks.push([resolve, reject]);
sendNotification();
});
}
}
}
Use with for-wait-of language feature:
async someFunction() {
const obs = ...;
const asyncIterable = {
[Symbol.asyncIterator]: () => asyncIterator(obs)
};
for await (const value of asyncIterable) {
console.log(value);
}
}
Use without for-wait-of language feature:
async someFunction() {
const obs = ...;
const it = asyncIterator(obs);
while (true) {
const { value, done } = await it.next();
if (done) {
break;
}
console.log(value);
}
}
that might just work, since take(1) completes the observable, then it is consumed by await, next one in line will produce the second emission to value2.
const observer= new Subject()
async function getStream(){
const value1 = await observer.pipe(take(1)).toPromise() // 0.25
const value2 = await observer.pipe(take(1)).toPromise() // 0.75
return [value1,value2]
}
getStream().then(values=>{
console.log(values)
})
//const obs = new Observable((observer) => {
setTimeout(()=>{observer.next(0.25)},1000);
setTimeout(()=>observer.next(0.75),2000);
UPDATE: Using subject to emit.

empty array outside nested resolve promise

im tring to push the return value of the resolve to a variable catWithItems which is outside the resolve. inside the resolve the catWithItems works as expected but when i console log catWithItems outside the loop it returns an empty array.
function categoriesSearch(req, res, next) {
let categories = req.batch_categories;
let catWithItems = [];
_.forEach(categories, (category) => {
return new Promise(resolve => {
pos.categoriesSearch(req.tenant, category.id)
.then(item => {
if(item) category.items = item[0];
return category;
})
.then(category => {
catWithItems.push(category);
console.log(catWithItems); //this is works inside here
return resolve(catWithItems);
});
});
});
console.log(catWithItems); //doesn't work returns empty array
res.json({categoryWithItems: catWithItems });
}
this is the pos.categoriesSearch module. it makes a api call to square.(this works as expected)
function categoriesSearch(tenant, category) {
let search_items_url = ${tenant.square.api.v2}/catalog/search,
apiKey = tenant.square.api.key,
payload = {
"object_types": ["ITEM"],
"query": {
"prefix_query": {
"attribute_name": "category_id",
"attribute_prefix": category
}
},
"search_max_page_limit": 1
},
conf = config(search_items_url, apiKey, payload);
return request.postAsync(conf)
.then(items => {
return items.body.objects;
});
}
Your not handling promises right. Try it this way.
function categoriesSearch(req, res, next) {
let categories = req.batch_categories;
let promiseArray = []; // create an array to throw your promises in
let catWithItems = [];
categories.map((category) => {
let promise = new Promise(resolve => {
pos.categoriesSearch(req.tenant, category.id)
.then(item => {
if(item) category.items = item[0];
return category;
})
.then(category => {
catWithItems.push(category);
console.log(catWithItems); //this is works inside here
return resolve(catWithItems);
});
});
promiseArray.push(promise) // add promises to array
});
// resolve all promises in parallel
Promise.all(promiseArray).then((resolved) => {
console.log(resolved);
res.json({categoryWithItems: catWithItems });
})
}
It should be much easier. Not sure if it works, but something to start with:
function categoriesSearch(req, res) {
const categoryWithItems$ = req.batch_categories.map(category =>
pos.categoriesSearch(req.tenant, category.id)
.then(item => ({ ...category, items: item[0] })
);
Promise.all(categoryWithItems$)
.then(categoryWithItems => res.json({ categoryWithItems });
}

How return a value after a forEach loop using Promises?

I need to know how to return a value after a forEach loop using Promises. In this moment, when I launch my main, I get :
[ Promise { <pending> }, Promise { <pending> } ]
(my sampleidlist contains only 2 records)
This is my code :
MongoClient.connect("mongodb://127.0.0.1/myproject", function(err, db) {
return db.collection('RUN').find({
"idRun": query.idRun
}).toArray()
.then((out) => {
var sampleidlist = out[0].SAMPLE_ID
var pazlist = []
// Promisearr is the array of promises where I try to push the promises
var Promisearr = []
// there is the function find_paz that return idPaz for every sampleId in sampleidlist
function find_paz(sampleid) {
// I return a new Promise for every sampleId
// I want to create an array of idPaz
return new Promise((resolve, reject) => {
db.collection('PATIENTS').find({
"SAMPLE_ID": sampleid
}).toArray()
.then((pazArr) => {
var singlepaz = []
singlepaz.push(pazArr[0].idPaz)
return singlepaz
})
.then((singlepaz) => {
pazlist.push(singlepaz)
})
})
}
// Here the forEach loop
sampleidlist.forEach(sampleid => {
Promisearr.push(
find_paz(sampleid)
)
})
Promise.resolve(Promisearr)
.then(Promise.all(Promisearr))
.then(value => {
// value return {promise<pending>}
// I want that value is the array of idPaz
console.log(value)
}).catch((err) => {
console.log('errored', err);
})
}).catch((err) => {
console.log('errored', err);
})
})
Any suggest?
Thank you very much :)
You have it mixed up between Promise.all and Promise.resolve. Here:
return db.collection('RUN').find({
"idRun": query.idRun
}).toArray()
.then((out) => {
var sampleidlist = out[0].SAMPLE_ID
var pazlist = []
var Promisearr = []
function find_paz(sampleid) {
return db.collection('PATIENTS').find({
"SAMPLE_ID": sampleid
}).toArray()
.then((pazArr) => {
var singlepaz = []
singlepaz.push(pazArr[0].idPaz)
return singlepaz
})
.then((singlepaz) => {
pazlist.push(singlepaz)
return;
})
})
}
Promise.all(sampleidlist.map(find_paz))
.then(values => {
//values is an array with all the promises resolved
//pazlist should have your data.
}).catch((err) => {
console.log('errored', err);
})
}).catch((err) => {
console.log('errored', err);
})
Give it a try, let me know if you need clarification or if it doesn't work.
You are using Promise.resolve() and Promise.all() the wrong way. You should just call Promise.all() then .then(), like this :
Promise.all(Promisearr).then(value =>
console.log(value)
)

How to return a single promise after for loop where every element of an array inside loop do multi async calls

I Have a array of objects which i need to clone with different values.
Those values i'll get from each promise finally after preparing main modified array of object i'll have to save this. So i many need this as one single promise.
I not sure how to do it.
Here is the example we need to clone oldUser data. Say old user has credit score = 100; but for new user default credit will be created randomly by system.
For each user in the array of users few details has to get updated using async call.
This is the requirement
function getUserCreditScore(user){
var url = '/someurl';
return $http.get(url).then(function(res){
user.creditScore = (res.data) ? res.data : 0;
});
}
function getUserRecomandations(user){
var url = '/someurl';
return $http.get(url).then(function(res){
user.recommendation = (res.data) ? res.data : 'basic recommendation';
});
}
function getUserHelpInfo(user){
var url = '/someurl';
return $http.get(url).then(function(res){
user.helpInfo = (res.data) ? res.data : 'Help Info';
});
}
function clone(){
var newUsers = angular.copy(oldUsers);
for (var i=0; i<newUsers.length; i++){
newUsers[i].id = undefined;
getUserCreditScore(newUsers[i]);
getUserRecommendation(newUsers[i]);
getUserHelpInfo(newUsers[i]);
}
var promises = _.map(newUsers, user => user.save());
$q.all(promises).then(function (data) {
console.log(data);
}
}
You'll need to Promise.all on an array of Promises that are returned by getScreditScore
something like
function getCreditScore(){
var url = '/someurl';
return $http.get(url).then(res => (res && res.data) ? res.data : res);
}
function clone(){
var newUsers = angular.copy(oldUsers);
Promise.all(
newUsers.map(newUser => {
newUser.id = undefined;
return getCreditScore()
.then(result => newUser.creditScore = result);
})
).then(results => // results will be an array of values returned by the get in getCreditScore(newUser)
Promise.all(newUsers.map(user => user.save()))
).then(data =>
console.log(data); // this will be the result of all the user.save
);
}
Note: the newUser.creditScore is set in the .then in the newUsers.map callback - (minimal change to my original answer)
Alternatively, passing user to getCreditScore
function getCreditScore(user){
var url = '/someurl';
return $http.get(url)
.then(res => (res && res.data) ? res.data : res)
.then(score => user.creditScore = score);
}
function clone(){
var newUsers = angular.copy(oldUsers);
Promise.all(
newUsers.map(newUser => {
newUser.id = undefined;
return getCreditScore(newUser);
})
).then(results => // results will be an array of values returned by the get in getCreditScore(newUser)
Promise.all(newUsers.map(user => user.save()))
).then(data =>
console.log(data); // this will be the result of all the user.save
);
}
Personally, I'd write the code
function getCreditScore(){
var url = '/someurl';
return $http.get(url).then(res => (res && res.data) ? res.data : res);
}
function clone(){
var newUsers = angular.copy(oldUsers);
Promise.all(
newUsers.map(newUser => {
newUser.id = undefined;
return getCreditScore()
.then(result => newUser.creditScore = result)
.then(() => newUser.save())
.then(() => newUser);
})
).then(data =>
console.log(data); // this will be the newUsers Array
);
}
This assumes, though, that you don't need to wait for all the $http.get before running the user.save() - in fact this may be a little (very little) more performant as the newUser.save and $http.get will run in tandem
Ok, I know your meaning, you want your every element of your array do something that is async.
So you can use map and Promise.all. Here is my code:
const asyncFunction = (item, cb) => {
setTimeout(() => {
console.log(`done with ${item}`);
cb();
}, 1000);
}
let requests = [1, 2, 3].map((item) => {
return new Promise((resolve) =>{
asyncFunction(item, resolve);
});
});
Promise.all(requests).then(() => console.log('done'));

Categories

Resources