MySQL Java JavaScript PHP Python HTML-CSS C-sharp

Crearea lanțurilor de promise-uri

Unul dintre avantajele promise-urilor este capacitatea lor de a crea lanțuri de promise-uri. Astfel, anterior am examinat utilizarea metodelor then() și catch() pentru primirea și tratarea rezultatelor și a erorilor operațiilor asincrone. Atunci când sunt executate, aceste metode generează un nou obiect Promise, pentru care, de asemenea, putem apela metodele then() și catch(), construind astfel un lanț de promise-uri. Acest lucru ne permite să tratăm mai multe operațiuni asincrone, una după alta.

promise.then(..).then(..).then(..)

Valoarea returnată din funcția-handler în metoda then() este transmisă apelului următor al metodei then() în lanț:

const helloPromise = new Promise(function(resolve){
       resolve("Hello");
})

const worldPromise = helloPromise.then(function(value){
       // returnăm o nouă valoare
       return value + " World";
});
const fdcPromise = worldPromise.then(function(value){
       // returnăm o nouă valoare
       return value + " from FDC.COM";
});
fdcPromise.then(function(finalValue){
       // primim valoarea finală
       console.log(finalValue);    // Salut Lume de la FDC.COM
});

Aici, pentru o mai mare claritate, întregul proces este împărțit în promise-uri separate: helloPromise, worldPromise și fdcPromise.

În primul rând, se creează promise-ul helloPromise:

const helloPromise = new Promise(function(resolve){
   resolve("Hello");
});

În operațiunea asincronă, prin apelul resolve("Hello"), promise-ul este trecut în starea fulfilled, adică executarea operațiunii a fost finalizată cu succes. Iar în exterior este transmisă valoarea "Hello".

Apoi, la promise-ul helloPromise se apelează metoda then():

const worldPromise = helloPromise.then(function(value){
       // returnăm o nouă valoare
       return value + " World";
});

Ca valoare a parametrului value, funcția handler primește șirul "Hello" și apoi returnează șirul "Hello World". Acest șir poate fi apoi obținut prin metoda then() a noului promise generat prin apelul helloPromise.then(), care aici este numit worldPromise.

Apoi, într-o manieră similară, la promise-ul worldPromise se apelează metoda then():

const fdcPromise = worldPromise.then(function(value){
       // returnăm o nouă valoare
       return value + "from FDC.COM";
});

Ca valoare a parametrului value, funcția handler primește șirul "Hello World" și apoi returnează șirul "Hello World from FDC.COM". Apelul worldPromise.then() returnează un nou promise fdcPromise.

În etapa finală, la promise-ul fdcPromise se apelează metoda then():

fdcPromise.then(function(finalValue){
   console.log(finalValue);    //Hello World from FDC.COM
});

Aici, prin parametrul finalValue, primim valoarea finală - șirul "Hello World from FDC.COM" și îl afișăm în consolă. După aceasta, lanțul este finalizat.

Pentru a scurta și a face lanțul mai clar, putem simplifica lanțul:

new Promise(resolve => resolve("Hello"))
.then(value => value + " World")
.then(value => value + " de la FDC.COM")
.then(finalValue => console.log(finalValue));

Tratarea erorilor

Pentru tratarea erorilor, la sfârșitul lanțului se adaugă metoda catch(), care, de asemenea, returnează un obiect Promise. Să examinăm un exemplu simplu:

function generateNumber(str){
   return new Promise((resolve, reject) => {
       const parsed = parseInt(str);
       if (isNaN(parsed)) reject("Nu este un număr");
       else resolve(parsed);
   });
};
function printNumber(str){
   generateNumber(str)
       .then(value => console.log(value))
       .catch(error => console.log(error));
}
printNumber("rty"); // Nu este un număr
printNumber("3");   // 3

În acest caz, funcția generateNumber() returnează un promise în care primim o valoare din exterior, încercăm să o convertim în număr. În funcția printNumber() apelăm această funcție și la promise-ul obținut construim un mic lanț din metodele then() și catch().

Dacă conversia șirului în număr în promise este reușită, numărul parsat este transmis în funcția resolve():

else resolve(parsed)

În acest caz, la primirea acestui rezultat, se activează metoda then(), care în acest caz afișează valoarea primită în consolă:

.then(value => console.log(value))

Metoda catch() nu se execută în absența erorilor.

Totuși, dacă valoarea transmisă nu poate fi convertită în număr, în promise se execută apelul:

if (isNaN(parsed)) reject("Nu este un număr");

În acest caz, metoda then() este ignorată, iar execuția trece la apelul:

.catch(error => console.log(error));

Tratarea erorilor în lanțul de promise-uri

Acum să complicăm lanțul. Să presupunem că în lanțul nostru se execută mai multe promise-uri:

function generateNumber(str){
   return new Promise((resolve, reject) => {
       const parsed = parseInt(str);
       if (isNaN(parsed)) reject("Nu este un număr");
       else resolve(parsed);
   });
};
function printNumber(str){
   generateNumber(str)
       .then(value => {
           if (value===4) throw "Număr nefast";
           return value * value;
       })
       .then(finalValue => console.log(`Rezultat: ${finalValue}`))
       .catch(error => console.error(error));
}
printNumber("rty"); // Nu este un număr
printNumber("3");   // Rezultat: 9
printNumber("4");   // Număr nefast
printNumber("5");   // Rezultat: 25

Aici, pentru simplitate, tot codul este inclus în funcția generateNumber(), care creează un lanț de promise-uri. În acest lanț de promise-uri, de asemenea, primim o valoare din exterior, încercăm să o convertim în număr, apoi calculăm pătratul său și îl afișăm în consolă. La sfârșitul lanțului se află metoda catch(). În această metodă se transmite un handler de erori, care primește eroarea și o afișează în consolă.

Astfel, dacă în lanțul de promise-uri, la unul dintre etape, se generează o eroare (din cauza funcționării interne a codului, de exemplu, la generarea unei erori cu ajutorul operatorului throw, sau la apelul funcției reject()), atunci toate apelurile ulterioare ale metodei then(), care conțin doar tratarea valorii, sunt ignorate, iar execuția lanțului trece la metoda catch().

De exemplu, la apelul funcției:

printNumber("rty"); // Nu este un număr

Returnarea Promise din catch

Totuși, trebuie menționat că, deoarece catch() returnează un obiect Promise, lanțul poate fi continuat și mai departe:

function generateNumber(str){
   return new Promise((resolve, reject) => {
       const parsed = parseInt(str);
       if (isNaN(parsed)) reject("Nu este un număr");
       else resolve(parsed);
   });
};
function printNumber(str){
   generateNumber(str)
       .then(value => value * value)
       .then(value => console.log(`Rezultat: ${value}`))
       .catch(error => console.error(error))
       .then(() => console.log("Lucrul a fost finalizat"));
}
printNumber("3");  
// Rezultat: 9
// Lucrul a fost finalizat

Și metoda then() după catch() va fi apelată, chiar dacă nu au avut loc erori și metoda catch() nu a fost executată.

Și chiar putem transmite din funcția-handler de erori din catch() o anumită valoare și să o primim prin metoda ulterioară then():

function generateNumber(str){
   return new Promise((resolve, reject) => {
       const parsed = parseInt(str);
       if (isNaN(parsed)) reject("Nu este un număr");
       else resolve(parsed);
   });
};
function printNumber(str){
   generateNumber(str)
       .then(value => value * value)
       .then(value => console.log(`Rezultat: ${value}`))
       .catch(error => {
           console.log(error);
           return 0;
       })
       .then(value => console.log("Cod de stare:", value));
}
printNumber("ert3");    // Nu este un număr
                       // Cod de stare: 0

Metoda finally

În afară de metodele then() și catch(), obiectul Promise pentru tratarea rezultatului oferă, de asemenea, metoda finally(). Această metodă este executată la sfârșitul lanțului de promise-uri, indiferent dacă a apărut o eroare sau executarea promise-ului a avut loc cu succes.

Ca parametru, metoda primește o funcție, care execută anumite acțiuni finale de tratare a funcționării promise-ului:

function generateNumber(str){
   return new Promise((resolve, reject) => {
       const parsed = parseInt(str);
       if (isNaN(parsed)) reject("Nu este un număr");
       else resolve(parsed);
   });
};
function printNumber(str){
   generateNumber(str)
   .then(value => console.log(value))
   .catch(error => console.log(error))
   .finally(() => console.log("Sfârșit"));
}

printNumber("3");
printNumber("triuy");

Aici ne adresăm de două ori la promise-ul returnat de funcția generateNumber. Într-un caz, șirul va fi convertit cu succes în număr, în celălalt caz - va apărea o eroare. Totuși, indiferent de absența sau prezența erorii, în ambele cazuri va fi executată metoda finally(), care va afișa în consolă șirul "Sfârșit".

Metoda finally() returnează un obiect Promise, deci după ea se poate continua lanțul:

function generateNumber(str){
   return new Promise((resolve, reject) => {
       const parsed = parseInt(str);
       if (isNaN(parsed)) reject("Nu este un număr");
       else resolve(parsed);
   });
};
function printNumber(str){
   generateNumber(str)
   .then(value => console.log(value))
   .catch(error => console.log(error))
   .finally(() => console.log("Executarea promise-ului a fost finalizată"))
   .then(() => console.log("Promise-ul încă funcționează"));
}
printNumber("3");

Ieșirea în consolă:

3
Executarea promise-ului a fost finalizată
Promise-ul încă funcționează

Merită de menționat că în metoda then() se pot de asemenea transmite date. Dar aceste date sunt transmise nu din metoda finally(), ci din metoda anterioară then() sau catch():

function generateNumber(str){
   return new Promise((resolve, reject) => {
       const parsed = parseInt(str);
       if (isNaN(parsed)) reject("Nu este un număr");
       else resolve(parsed);
   });
};
function printNumber(str){
   generateNumber(str)
   .then(value => {
       console.log(value);
       return "salut de la then";
   })
   .catch(error => {
       console.log(error);
       return "salut de la catch";
   })
   .finally(() => {
       console.log("Sfârșit");
       return "salut de la finally";
   })
   .then(message => console.log(message));
}
printNumber("3");
3
Sfârșit
salut de la then
← Lecția anterioară Lecția următoare →