Poikkeukset promise-ketjuissa JavaScriptissä

Olkoon jostain syystä promiseemme päätyy virheeseen:

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

Tässä tapauksessa koodin suoritus siirtyy välittömästi siihen then:iin, jossa on virheen käsittelijäfunktio, tai ensimmäiseen catch:iin, kumpi tulee vastaan ensin.

Tässä on esimerkki ensimmäisestä tilanteesta:

javascriptpromise.then(
  function(result) {
    return result + '1';
  }
).then(
  function(result) {
    return result + '2';
  },
  function(error) {
    // suoritus siirtyy välittömästi tänne
  }
).then(
  function(result) {
    console.log(result);
  }
);

Tässä on esimerkki toisesta tilanteesta:

javascriptpromise.then(
  function(result) {
    return result + '1';
  }
).then(
  function(result) {
    return result + '2';
  }
).catch(
  function(error) {
    // suoritus siirtyy välittömästi tänne
  }
).then(
  function(result) {
    console.log(result);
  }
);

Käsittelijäfunktiolla on kaksi vaihtoehtoista toimintatapaa: jos se selviytyy poikkeustilanteesta, se voi palauttaa tuloksen return:lla ja suoritus jatkuu ketjussa eteenpäin. Jos se ei selviydy virheestä, se voi joko olla palauttamatta mitään tai heittää poikkeuksen throw:lla. Tässä tapauksessa suoritus siirtyy seuraavaan virheen käsittelijään (then:iin tai catch:iin - kumpi tulee vastaan ensin).

Yleensä kaikki ketjun virheet käsitellään yhdessä paikassa: ketjun loppuun sijoitetaan catch:

javascriptpromise.then(
  function(result) {
    return result + '1';
  }
).then(
  function(result) {
    return result + '2';
  }
).catch(
  function(error) {
    // päädymme tänne virheen sattuessa
  }
);

Tässä tapauksessa poikkeus voi ilmetä itse promisessa, tai se voidaan heittää throw:lla missä tahansa ketjun lenkissä:

javascriptpromise.then(
  function(result) {
    return result + '1';
  }
).then(
  function(result) {
    if (kaikkiHyvin) {
      return result + '2';
    } else {
      throw new Error('virhe'); // siirrytään lähimpään käsittelijään
    }
  }
)
.then(
  function(result) {
    return result + '3';
  }
).catch(
  function(error) {
    // lähin käsittelijä
  }
);

Huomioi, että catch:ia tarvitaan nimenomaan virheen diagnosointia varten: onko se ratkaistavissa vai ei. Jos virhe on ratkaistavissa, catch:in pitää lähettää sen ratkaisu seuraavalle then:ille. Mutta jos se ei ole ratkaistavissa (tai tämä catch ei yksinkertaisesti tiedä miten se ratkaistaan), meidän pitää joko olla palauttamatta mitään tai heittää poikkeus:

javascriptpromise.then(
  function(result) {
    return result + '1';
  }
).then(
  function(result) {
    return result + '2';
  }
).catch(
  function(error) {
    if (virheRatkaistavissa) {
      return 'data'; // lähetetään seuraavalle then:ille
    } else {
      // ei palauteta mitään tai heitetään poikkeus
    }
  }
).then(
  function(result) {
    // tässä ratkaistaan virhe
  }
);