I'm having a hard time getting a chain of promises in a for loop to execute sequentially. I have an array and 5 functions that all return promises. For each element in the array, i'm creating 5 parameters and each parameter goes into each 5 functions which need to be executed sequentially before proceeding to the next item in the array. I need to promises to execute in the following manner.
and so on.
const array = ['a','b','c','d','e']
evalParam(param,callback){
//do things with param
callback(true);
func1(param) {
return new Promise((resolve, reject) =>{
this.evalParam(param, resolve);
});
}
.
.
.
func5(param) {
return new Promise((resolve, reject) =>{
this.evalParam(param, resolve);
});
}
lastFunc(errors)
{
//Do things with errors
console.log(errors)
}
executeChain(array){
errors : any[] = []
return new Promise(resolve,reject) => {
return new Promise(resolve,reject) => {
for (let item of array){
const param1 = this.createParam1(item)
const param2 = this.createParam2(item)
const param3 = this.createParam3(item)
const param4 = this.createParam4(item)
const param5 = this.createParam5(item)
Promise.resolve()
.then(() => {
func1(param1) }
.then((val) => {
if (val) {
func2(param2)
} else {
errors.push("func1 failed with param: " + param1)
}
.
.
.
.then((val) => {
if (val){
func5(param5)
else {
errors.push("func5 failed with param: " + param5)
}
})
} // End for loop
.then(()=> {
resolve(errors)
})
}
Any help would be appreciated.
I would suggest few things:
async/await
which works perfectly for such cases and makes your code much clearerThe solution will look similar to:
const paramHandlers: Function[] = [
// func1
() => {},
// func2
() => {}
// ...
];
async function executeChain(array: any[]): Promise<any> {
const errors = [];
for (const i in array) {
try {
// wait for item to be processed or failed with error
// and continue
await executeItem(array[i]);
} catch (error) {
// one of param handlers failed with 'error'
errors.push(error);
}
}
return errors;
}
async function executeItem(arrayValue: any): Promise<any> {
const params = createParams(arrayValue);
for (const i in params) {
const param = params[i];
// lookup corresponding handler by index
const paramHandler = paramHandlers[i];
// execute function and wait for promise to resolve
// for loop will not continue to next execution until promise resolved
// if paramHandler's promise will be rejected,
// then executeItem will return rejected Promise, having same error
await paramHandler.apply(param);
}
}
function createParams(value: any): any[] {
return [
/*
createParam1(value),
createParam2(value),
...
*/
];
}
If you still want to use promises, then executeItem
can look as following:
function executeItem(arrayValue: any): Promise<any> {
const params = createParams(arrayValue);
return params.reduce((result, param, i) => {
const paramHandler = paramHandlers[i];
return result.then(() => paramHandler.apply(param));
}, Promise.resolve());
}
you can do similar stuff for executeChain
.
Please also check this question. It contains extensive info on sequential promises processing.