Изключения в вериги от промени в JavaScript

Нека по някакви причини нашият промис завърши с грешка:

javascriptlet promise = new Promise(function(resolve, reject) {
  setTimeout(function() {
    reject('error');
  }, 3000);
});

В този случай изпълнението на кода веднага ще премине към оня then, в който има функция-обработчик на грешката, либо към първия catch, гледайки кое ще се срещне по-рано.

Ето пример за първата ситуация:

javascriptpromise.then(
  function(result) {
    return result + '1';
  }
).then(
  function(result) {
    return result + '2';
  },
  function(error) {
    // изпълнението веднага ще премине тук
  }
).then(
  function(result) {
    console.log(result);
  }
);

Ето пример за втората ситуация:

javascriptpromise.then(
  function(result) {
    return result + '1';
  }
).then(
  function(result) {
    return result + '2';
  }
).catch(
  function(error) {
    // изпълнението веднага ще премине тук
  }
).then(
  function(result) {
    console.log(result);
  }
);

Функцията-обработчик има два варианта на действие: ако тя се е справила с изключителната ситуация, то може да върне резултат чрез return и изпълнението ще продължи по-нататък по веригата. Ако пък не се е справила с грешката, то може или да не върне нищо, или да хвърли изключение чрез throw. В този случай изпълнението ще премине към следващия прихващач на грешки (в then или catch - което се срещне по-рано).

По правило всички грешки във веригата се прихващат на едно място: в края на веригата се поставя catch:

javascriptpromise.then(
  function(result) {
    return result + '1';
  }
).then(
  function(result) {
    return result + '2';
  }
).catch(
  function(error) {
    // ще попаднем тук в случай на грешка
  }
);

При това изключение може да възникне в самия промис, или да бъде хвърлено чрез throw във всяка връзка от веригата:

javascriptpromise.then(
  function(result) {
    return result + '1';
  }
).then(
  function(result) {
    if (всичкоДобре) {
      return result + '2';
    } else {
      throw new Error('грешка'); // преминаваме към най-близкия прихващач
    }
  }
)
.then(
  function(result) {
    return result + '3';
  }
).catch(
  function(error) {
    // най-близкият прихващач
  }
);

Имайте предвид, че catch е необходим точно за диагностика на грешката: решимима ли е или не. Ако грешката е решимима, то catch трябва да предаде нейното решение на следващия след себе си then. А ако не е решимима (или този catch просто не знае как да я реши), то трябва или да не върнем нищо, или да хвърлим изключение:

javascriptpromise.then(
  function(result) {
    return result + '1';
  }
).then(
  function(result) {
    return result + '2';
  }
).catch(
  function(error) {
    if (грешкатаЕРешимима) {
      return 'данни'; // изпращаме на следващия then
    } else {
      // не връщаме нищо или хвърляме изключение
    }
  }
).then(
  function(result) {
    // тук решаваме грешката
  }
);