Introducere în Promisiuni
O promisiune (promise) este un obiect care reprezintă rezultatul final (fie succes, fie eșec) al unei operațiuni asincrone. Simplificat, o operațiune asincronă este o acțiune care se execută independent de codul înconjurător care o apelează și nu blochează execuția codului care o cheamă.
O promisiune poate fi în una dintre următoarele stări:
- Starea de așteptare (pending): Este starea inițială, promisiunea a fost creată, dar execuția nu a fost încă finalizată
- Starea îndeplinită (fulfilled): Acțiunea pe care o reprezintă promisiunea a fost finalizată cu succes
- Starea respinsă (rejected): A apărut o eroare în timpul execuției acțiunii pe care o reprezintă promisiunea
Pentru a crea o promisiune se folosește constructorul Promise:
new Promise(executor)
Constructorul acceptă o funcție ca parametru, funcție care este executată la crearea promisiunii. De obicei, această funcție reprezintă operațiuni asincrone care necesită timp. De exemplu, să definim cea mai simplă promisiune:
const myPromise = new Promise(function(){
console.log("Executarea unei operațiuni asincrone");
});
Aici, funcția pur și simplu afișează un mesaj pe consolă. Astfel, la executarea acestui cod, vom vedea mesajul "Executarea unei operațiuni asincrone" pe consolă.
Când se creează o promisiune și funcția acesteia încă nu a început să se execute, promisiunea trece în starea "pending", adică așteaptă să fie executată.
Pentru a emula asincronitatea, să definim câteva promisiuni:
const myPromise3000 = new Promise(function(){
console.log("[myPromise3000] Executarea unei operațiuni asincrone");
setTimeout(()=>console.log("[myPromise3000] Finalizarea unei operațiuni asincrone"), 3000);
});
const myPromise1000 = new Promise(function(){
console.log("[myPromise1000] Executarea unei operațiuni asincrone");
setTimeout(()=>console.log("[myPromise1000] Finalizarea unei operațiuni asincrone"), 1000);
});
const myPromise2000 = new Promise(function(){
console.log("[myPromise2000] Executarea unei operațiuni asincrone");
setTimeout(()=>console.log("[myPromise2000] Finalizarea unei operațiuni asincrone"), 2000);
});
Aici sunt definite trei promisiuni identice. Pentru ca fiecare dintre ele să nu se execute imediat, folosesc funcția setTimeout cu o întârziere de câteva secunde. Durata întârzierii diferă pentru diferite promisiuni. Și în acest caz, vom obține următorul output pe consolă:
[myPromise3000] Executarea unei operațiuni asincrone
[myPromise1000] Executarea unei operațiuni asincrone
[myPromise2000] Executarea unei operațiuni asincrone
[myPromise1000] Finalizarea unei operațiuni asincrone
[myPromise2000] Finalizarea unei operațiuni asincrone
[myPromise3000] Finalizarea unei operațiuni asincrone
Aici vedem că primul a început să se execute promisiunea myPromise3000, dar a și finalizat ultima, deoarece are cel mai mare timp de întârziere - 3 secunde. Totuși, întârzierea sa nu a împiedicat executarea celorlalte promisiuni.
resolve și reject
De obicei, funcția care este transmisă constructorului Promise acceptă două parametri:
const myPromise = new Promise(function(resolve, reject){
console.log("Executarea unei operațiuni asincrone");
});
Ambii parametri - resolve și reject - sunt, de asemenea, funcții. Fiecare dintre aceste funcții acceptă un parametru de orice tip.
Primul parametru, funcția resolve, este apelată în cazul unui succes. Putem transmite în aceasta o valoare pe care o putem obține ca rezultat al unui succes.
Al doilea parametru, funcția reject, este apelată în cazul unei erori. Putem transmite în aceasta o valoare care reprezintă informații despre eroare.
Execuția reușită a unei promisiuni
Așadar, primul parametru al funcției din constructorul Promise - funcția resolve - este executată la un succes. În această funcție, de obicei, se transmite o valoare care reprezintă rezultatul operațiunii în cazul unui succes. Această valoare poate reprezenta orice obiect. De exemplu, transmitem în această funcție un șir de caractere:
const myPromise = new Promise(function(resolve){
console.log("Executarea unei operațiuni asincrone");
resolve("Salut lume!");
});
Funcția resolve() este apelată la sfârșitul operațiunii executate după toate acțiunile. Când se apelează această funcție, promisiunea trece în starea fulfilled (executată cu succes).
Totuși, trebuie să menționăm că, teoretic, putem returna un rezultat din funcție, dar practic nu ar avea sens:
const myPromise = new Promise(function(resolve, reject){
console.log("Executarea unei operațiuni asincrone");
return "Salut lume!";
});
Valoarea returnată nu poate fi transmisă în afară. Și, dacă într-adevăr trebuie să returnăm un anumit rezultat, acesta trebuie transmis funcției resolve().
Transmiterea informațiilor despre eroare
Al doilea parametru al funcției din constructorul Promise este funcția reject, care este apelată când apare o eroare. În această funcție, de obicei, se transmite o informație despre eroare, care poate reprezenta orice obiect. De exemplu:
const myPromise = new Promise(function(resolve, reject){
console.log("Executarea unei operațiuni asincrone");
reject("Au fost transmise date incorecte");
});
Când se apelează funcția reject(), promisiunea trece în starea rejected (finalizată cu eroare).
Combinarea resolve și reject
Evident, putem defini o logică în care, în funcție de anumite condiții, vor fi executate ambele funcții:
const x = 4;
const y = 0;
const myPromise = new Promise(function(resolve, reject){
if(y === 0) {
reject("Au fost transmise date incorecte");
}
else{
const z = x / y;
resolve(z);
}
});
În acest caz, dacă valoarea constantei y este 0, atunci comunicăm despre eroare, apelând funcția reject(). Dacă nu este 0, atunci executăm operația de împărțire și transmitem rezultatul funcției resolve().