1

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.

  • item 1
    • func1(param1)
    • If func1 succeeds continue to func2 else log errors and stop.
    • If func2 succeeds continue to func3 else log errors ...
  • item 2 ....

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.

Duncan Gichimu
  • 456
  • 1
  • 5
  • 17

1 Answers1

3

I would suggest few things:

  • Separate your code into smaller functions
  • Start using async/await which works perfectly for such cases and makes your code much clearer

The 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.

udalmik
  • 7,838
  • 26
  • 40