-
-
Save anvk/5602ec398e4fdc521e2bf9940fd90f84 to your computer and use it in GitHub Desktop.
function asyncFunc(e) { | |
return new Promise((resolve, reject) => { | |
setTimeout(() => resolve(e), e * 1000); | |
}); | |
} | |
const arr = [1, 2, 3]; | |
let final = []; | |
function workMyCollection(arr) { | |
return arr.reduce((promise, item) => { | |
return promise | |
.then((result) => { | |
console.log(`item ${item}`); | |
return asyncFunc(item).then(result => final.push(result)); | |
}) | |
.catch(console.error); | |
}, Promise.resolve()); | |
} | |
workMyCollection(arr) | |
.then(() => console.log(`FINAL RESULT is ${final}`)); |
Likewise! Many thanks.
I made a few changes to the workMyCollection
:
function workMyCollection(arr) {
return arr.reduce((promise, item) => {
return promise
.then((result) => {
// help you to understand what's result
console.log(`A: result ${result}, item ${item}`)
return asyncFunc(item).then(result => {
final.push(result)
// print result and item
console.log(`B: result ${result}, item ${item}`)
// add a new return value
return result + " Done"
})
})
.catch(console.error)
}, Promise.resolve())
}
The new function will help you to understand the sequence better, which outputs following logs:
A: result undefined, item 1
B: result 1, item 1
A: result 1 Done, item 2
B: result 2, item 2
A: result 2 Done, item 3
B: result 3, item 3
Thanks for sharing. I've taken your code and refactored it with a more functional approach (no let
to keep state, we can use the data contained in the promise itself). I've called it promiseMap
(maybe promiseSequentialMap
would be more precise):
https://gist.github.com/tokland/71c483c89903da417d7062af009da571
Great! Thank you, this helpme a lot with a problem i had!
This one line Promise.all([1, 2, 3, 4, 5].map(asyncFunc))
does exactly the same . Question: how do you compose different functions in sequential order ?
@izinin it doesn't make the same. it looks like doing the same because each time the time increases, make it random, and you would see that the execution is not sequential.
@izinin you can use reduce to wait for the first asyncFunc
to resolve and then continue:
function getInSequence(array, asyncFunc) {
return array.reduce((previous, current) => (
previous.then(accumulator => (
asyncFunc(current).then(result => accumulator.concat(result))
))
), Promise.resolve([]));
}
Notice that you pass the accumulator through the Promise.resolve( [] )
and it concats the result of the asyncFunc
to it, in the respective order.
Keep in mind that this function will not return the accumulator result right away, it requires an await
handler inside an async function
to wait for "accumulated promise" to resolve and to handle Promises' errors.
var userArray = Object.keys(currentUser);
userArray.reduce((promisechain, value, index) => {
return promisechain.then(() => {
return new Promise((resolve) => {
setTimeout((v,i)=> {
console.log(v,i)
resolve()
},1000,value,index)
})
})
}, Promise.resolve())
Thank you, really helped me!
reducing example to nearest simplest form:
[1,2,3].reduce((promise,item) => {
return promise.then(() => {
return new Promise((resolve, reject)=> {
resolve(item);
})
})
},Promise.resolve())
await array.reduce(async (promise, item) => {
await promise;
return asyncFunction(item);
}, true);
I know the goal is to use reduce/be functional here but just to point out using async function and a loop to make sure it works the same way Promise.all
does in the end with how it resolves
async function resolveSequentially(arr) {
const results = [];
for (const v of arr) {
if (typeof v === 'function') {
results.push(await v());
} else {
results.push(await v);
}
}
return results;
}
or the reduce
parallel
function resolveSequentially(arr) {
let r = Promise.resolve();
return Promise.all(
arr.reduce((p, c) => {
r = r.then(() => (typeof c === 'function' ? c() : c));
p.push(r);
return p;
}, []),
);
}
it's friday 4:50pm and this came in at the perfect time. thank you so much!!
Hey seriously. Echoing the above thanks!
Using reduce
for this makes it harder than it has to be. It's not very easy on the eyes and mind.
I'd prefer something like this if await / async
is available.
// functions is an array of functions that return a promise.
async function runInSequence(functions) {
const results = [];
for (const fn of functions) {
results.push(await fn());
}
return results;
}
And we can use it like this:
function promisedFunction(delay, value) {
return new Promise(resolve => {
setTimeout(() => resolve(value), delay);
});
}
console.time("execution");
const results = await runInSequence([
promisedFunction.bind(this, 1000, 1),
promisedFunction.bind(this, 1000, 2),
promisedFunction.bind(this, 1000, 3)
]);
console.timeEnd("execution"); // execution: 3000 ms (approx)
console.log(results); // [1, 2, 3]
Thanks. Helped me a lot to solution duplicate primary key constraint in save() method with Typeform. The parallel process was my issue and I changed my Promise.all( ) loop, for this fn, and it works great.
My pay:
class TasksService {
static async execute(context, tasks) {
let results = [];
await tasks.reduce((promise, task) => {
return promise
.then((result) => {
return TasksService.asyncFunc(task).then(r => {
results.push(r.bind(context)())
});
})
}, Promise.resolve());
return results;
}
static asyncFunc(f) {
return new Promise((resolve, reject) => {
let task = f;
let time = 0;
if(typeof(task) !== 'function') {
task = f.task;
time = f.time;
}
setTimeout(() => resolve(task), time);
});
}
}
module.exports = TasksService;
Thank you !! This example really helped me