0

Promise – Poznaj magię obietnic – JavaScript

Jak działają promisy

Zamknij oczy i wyobraź sobie że jesteś uczniem, Twój nauczyciel obiecał Wam że puści Was 15 minut szybciej jeśli do tego czasu zdążycie skończyć wszystkie zadania z dzisiejszego tematu. To jest właśnie promise. W momencie żłożenia obietnicy  przez nauczyciela, nie wiesz czy zostanie ona spełniona. Dlatego właśnie promise posiada trzy stany (state):

  • pending – Jest to początkowy stan, po złożeniu obietnicy.
  • fulfilled – stan ten reprezentuje pozytywne zakończenie obietnicy.
  • rejected – ten stan reprezentuje  negatywne zakończenie obietnicy.

Co ważne, gdy promise osiągnie stan fulfilled lub rejected staje się on niezdolny do zmiany ( immutable). Pozostaję już taki na zawsze.

Historia promisów

Pierwsze implementacje promise pojawiły się we wczesnych latach 80, w językach takich jak Prolog oraz MultiLisp. Słowo Promise zostało wymyślone przez Barbara Liskov oraz Liuba Shrira w 1988r.

W świecie JavaScript koncept ten zaczął stawać się popularny, na początku 2011 r. za sprawą jQuery Deferred Objects. Deferred Objects posiadają bardzo podobny koncept, co promisy. Jednak nie implementują nowego, czytelniejszego sposobu ECMAScript na radzenie sobie z callback’ami.

Składnia

Przełóżmy wcześniejszy przykład na kod:

var tasksClosed = false;

// Promise
var weWillGetFree = new Promise(
    function (resolve, reject) {
        if ( tasksClosed ) {
            var msg = {
                text: 'Dzieci wesoło wybiegły ze szkoły..',
            };
            resolve( msg ); // fulfilled
        } else {
            var reason = new Error( 'Life is brutal!' );
            reject( reason ); // reject
        }

    }
);

Na początku zadeklarowaliśmy zmienną tasksClosed odpowiadającą za stan wykonania ćwiczeń. Przypisaliśmy jej wartość false. Następnie przypisaliśmy konstruktor Promise do zmiennej weWillGetFree. Konstruktor przyjmuje funkcje anonimową, która posiada 2 parametry.

Następnie w ciele funkcji sprawdzamy wartość tasksClosed. Gdy spełnia warunek tworzymy obiekt msg, oraz wywołujemy funkcje resolve, której przesyłamy obiekt msg. Gdy warunek nie został spełniony tworzymy nowy obiekt Error, wraz z treścią jako parametr oraz wywołujemy funkcję reject wraz z przekazanym errorem.

 

Wywołanie promise

Teraz gdy mamy już Promise wywołajmy go:

// call our promise

var checkTasks = () => 
{
  willWeBeFree
      .then( ( fulfilled ) => 
           {
             console.log( fulfilled );
              //Output: Dzieci wesoło wybiegły ze szkoły..
           } )
      .catch( ( error ) => 
           { 
             console.log( error.message ); 
              //Output:  Life is brutal!
           } );
}

checkTasks();

 

Tworzymy funkcję która konsumuje w swoim wnętrzu promise’a. Chcemy wykonać jakąś akcję w momencie w którym obietnica przyjmie stan fulfilled lub rejected. Dlatego wywołujemy .then() oraz .catch() które odpowiadają za obsługę zmiany stanu.

.then wywołuje się w momencie w którym Promise uzyska stan fulfilled. A więc w parametrze fulfilled znajdują się dane które przekazaliśmy w resolve( msg ), a więc będzie to kawałek tekstu piosenki.

.catch() odpowiada za wyłapywanie błędów, a dokładniej za sprawdzanie czy został wywołany reject, a sam promise przyjął stan rejected. Jeśli tak się stanie catch zwróci nam to co przekazaliśmy do funcji reject. W naszym wypadku będzie to smutny cytat

 

Łączenie obietnic

Wyobraźmy sobie teraz, że umówiliście się na papierosa + piwko w parku z kolegą, jeśli uda wam się zakończyć lekcję szybciej.

// 2nd promise
var goDrunk = function () 
{
    return new Promise(
        function (resolve, reject) 
        {
            var message = 'Zapaliły papierosy, wyciągneły flaszki';
            resolve(message);
        }
    );
};

Jak pewnie zauważyłeś, niezdefiniowaliśmy w tym wypadku reject, co jest opcjonalne. Co więcej możemy ten przykład jeszcze skrócić używając Promise.resolve().

// 2nd promise shorten ver.
var goDrunk = function () 
{
   var message = 'Zapaliły papierosy, wyciągneły flaszki';
   return Promise.resolve( message );
}

Ok, a więc przyszedł czas na połączenie naszych promise’ów:

// call our promise

var checkTasks = () => 
{
  willWeBeFree
      .then( goDrunk ) 
      .then( ( fulfilled ) => 
           {
             console.log( fulfilled );
              //Output: Zapaliły papierosy, wyciągneły flaszki
           } )
      .catch( ( error ) => 
           { 
             console.log( error.message ); 
              //Output:  Life is brutal!
           } );
}

checkTasks();

W taki łatwy sposób można łączyć ze soba promise, wystarczy dodać następne .then(), wynika to z tego że Promise zwraca obiekt nowego promise.

admin