0

I am recursively calling a function which returns a Promise, but i am noticing that the next then is called even if i am rejecting with error. Below is the relevant part of the code.

  const applyFilters = (counter) => {
    return new Promise((resolve, reject) => {
      let filter = filters[counter];
      if(filter) {
        applyStep(filter).then(promiseTimeout(filter.delay), function(err) {
          console.log('reject with error');
          reject(err);
        }).then(function(res) {
          console.log('still executing after reject');
          resolve(applyFilters(++counter).catch(function(err) {
            reject(err);
          }));
        });
      } else {
        resolve(true);
      }
    });
  };

  const applyStep = (step) => {
    if(step.step_type == 'filter') {
      return worksheet.applyFilterAsync(step.name, values, 'replace');
    } else if(step.step_type == 'parameter') {
      return workbook.changeParameterValueAsync(`${step.name}`, value);
    } else {
      return Promise.resolve(true);
    }
  };

I am seeing on console

reject with error
still executing after reject

Is this the expected behaviour, may be I am missing something. Any help in understating this further will be really great. Thanks.

opensource-developer
  • 2,826
  • 4
  • 38
  • 88
  • You are rejecting `applyFilters`, but the asynchronous `applyStep` continues on with the `.then()` that logs out `still executing after reject`. – Randy Casburn Nov 04 '20 at 16:57
  • Hi Randy, isn't the sequence of executions 1) applystep 2) promiseTimeout 3) second then in case of success and in case the apllystep has error the execution stops and does not call the second then? I have updated the question with definition of applyStep which also returns a promise – opensource-developer Nov 04 '20 at 17:01
  • Do you know how to use a debugger? Setting breakpoints and stepping through code is the way to answer that question. – Randy Casburn Nov 04 '20 at 17:04

1 Answers1

0

You are passing the second callback to then, which handles the error (in this case by rejecting the outer promise), and then fulfills the promise returned by the then() call with the callback return value (undefined). The next then() in the chain will be executed once that promise is fulfilled.

I could tell you how to work around this problem by using a different then/catch structure, but really you need to avoid the Promise constructor antipattern here!

function applyFilters(counter) {
  if (counter >= filter.length)
    return Promise.resolve(true);
  const filter = filters[counter];
  return applyStep(filter)
    .then(promiseTimeout(filter.delay))
    .then(res => applyFilters(++counter));
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Thanks @Bergi for your reply. I want to catch the errors that could happen during the execution of applyStep in which the the second function argument is the error handler. If i follow your suggestion i am not able to do that. Is there any workaround for this? – opensource-developer Nov 04 '20 at 21:53
  • "*`console.log('reject with error'); reject(err);`*" is not actually *handling* the error, is it? It's just "rethrowing" to reject the promise returned from `applyFilters`, same as what the code in my answer does. What errors (from where) do you want to handle, and how? – Bergi Nov 04 '20 at 21:59
  • yes, i want to store the `err` in an `array` and then later process it in the catch block which calls `applyFilters` – opensource-developer Nov 04 '20 at 22:01
  • sorry for all my questions, i am new to implementing promise chains, i did not understand by what you meant `The next then() in the chain will be executed once that promise is fulfilled`. in my case when the error happens and i reject the next then should not at all be called correct? – opensource-developer Nov 04 '20 at 22:04
  • @opensource-developer You're not rejecting the promise that the next `then()` is chained to. You're `reject()`ing the `new Promise`. – Bergi Nov 04 '20 at 22:18
  • @opensource-developer Not certain what you mean by an array. Are you actually trying to continue the filter chain, but record the failures in an array? Nothing in your original code hints at that. Normally, you'd just call `applyFilters(0).then(res => console.log('success'), err => console.error('one filter failed:', err))` – Bergi Nov 04 '20 at 22:21
  • Thanks for the clarification it makes more sense to me now. Thats correct, i am trying to record the failures in an array but since the code was not working i did no update it with my error handling code yet. – opensource-developer Nov 04 '20 at 22:23
  • so instead of reject should i use `throw new Error` then? – opensource-developer Nov 04 '20 at 22:23