В част 1 от тази серия разбрахме защо бяха въведени Promises. Знаем, че Promise API беше въведен като по-добра парадигма за работа с Asynchronous JS. Тук ще разберем какво представляват обещанията и как да създаваме обещания с прост пример и по-късно ще разгледаме по-практичен пример.

И така, какво е обещание?

Представете си една сутрин на работа, ваш колега ви се обажда и ви моли да направите услуга. Той трябва да отидете до паркинга на офиса и да проверите дали има свободно място. Тъй като мястото за паркиране е ограничено, ако няма място, той не трябва да губи време и може да паркира някъде другаде.

Вие ОБЕЩАВАТЕ, че ще направите това.

Отивате на паркинга, за да проверите за свободно място.

Какви са различните сценарии, които могат да се разиграят?

Или има отворено място, или не. Обаждате се на колегата и го уведомявате.

Във всеки случай вашето обещание е изпълнено.

Има ли друг сценарий? Представете си, че асансьорът е повреден, когато сте на път към паркинга. А вашият офис е на най-горния етаж на сградата. Ако сте като мен, тогава нямате проблем да слизате по стълбите, но да се връщате... това е съвсем друго нещо. Така че вие ​​се обаждате обратно на колегата си и го уведомявате, че всъщност не сте могли да проверите за открито място за паркиране, тъй като асансьорът е бил повреден.

В този случай вашето обещание към колегата е неизпълнено.

Макар и много груби, това са обещанията накратко.

Сега нека преминем към техническата страна на нещата, използвайки горния пример.

Според MDN:

Обектът Promise представлява евентуалното завършване (или неуспех) на асинхронна операция и нейната произтичаща стойност.

Вече засегнахме асинхронните функции. И знаете, че асинхронна функция ще бъде поставена на опашка и в крайна сметка ще бъде изпълнена (завършена). След като вашата асинхронна функция бъде завършена, тя ще се върне с резултат, ако има такъв. Това представлява обектът на обещание.

Какво означава това в контекста на нашия пример?

Тук обектът Обещание се отнася до действителното обещание, което сте дали на ваш колега да проверите за свободно място за паркиране.

Задачата да отидете до паркинга, да проверите за свободно място, да се обадите обратно на колегата си, за да го уведомите за наличността на място, може да се счита за асинхронна операция. Получената стойност може да бъде вярно/невярно в зависимост от наличността на пространството.

Как ще изглежда в код? Нека да разгледаме

Нека го разбием

Можете да създадете Promise обект, като използвате ключовата дума new.

Функцията, предавана на конструктора, се нарича изпълнител.
Когато се създаде ново обещание, изпълнителят се стартира автоматично. Той съдържа кода, който в крайна сметка трябва да произведе резултата. В нашия случай отиване до паркинга и проверка за свободно място.

Обвихме изпълнителявътре в setTimout функция, така че да се изпълнява асинхронно.

Изпълнителятима 2 параметъра съответно разрешаванеи отхвърляне. Те са обратни извиквания и ще бъдат изпълнени, след като нашата изпълнителна функция има резултат. Според нашия пример: след като разберете дали дадено място е налично/не.

В зависимост от наличността на паркомясто се обаждате на resolve(true) или resolve(false). Това означава, че сте отишли ​​на паркинга и сте се върнали с резултат. Вие изпълнихте обещанието си.

Но както обсъдихме, има 3-та опция, при която обещанието ви може да се е провалило. Нека да разгледаме кода за това

В този случай не се връщате с резултат. Вместо това хвърляте грешка. И така, вашето обещание е отхвърлено.

Обектът promise , върнат чрез извикване на конструктора new Promise, има 2 вътрешни свойства:

  1. състояние:Първоначално състоянието е предстоящо. В зависимост от това кое обратно извикване е извикано, или разреши/отхвърли, състоянието ще се промени съответно на изпълнено/отхвърлено.
  2. резултат: Стойността, която се предава на обратното извикване. В нашия случай вярно/невярно.

Важно е да се отбележи, че едно обещание може само да разрешава или отхвърля

Също така всяка промяна на състоянието е окончателна и всички следващи извиквания за разрешаване и отхвърляне се игнорират.

Това означава, че ако пропуснем оператора return в горния пример, изпълнителят ще изпълни до последния оператор (т.е. или resolve(true) или resolve(false)). Но независимо от това, състояниетона обещанието пак ще бъде отхвърлено и резултатътще бъде създадения обект за грешка .

Добре, научихме се да създаваме обещание. Знаем, че обещаващият обект представлява стойността, върната от евентуалното завършване на нашата асинхронна операция (копиране-поставено отгоре ;)). Но как може да се консумира тази стойност?

В нашия пример потребителят е наш колега, който ни е помолил да изпълним цялата тази задача. Как ще може да изконсумира обещанието, след като е изпълнено/отхвърлено?

За да създадем потребител, използваме методите then/catch/finally.

Синтаксисът на then е както следва:

Методът then има 2 аргумента. И двете са функции.

Първата функция се изпълнява, когато обещанието е разрешено.
Втората функция се изпълнява, когато обещанието е отхвърлено.
result/error ще бъде стойността, върната от обещанието.

Методът catch има само 1 аргумент, който ще бъде изпълнен, ако обещанието бъде отхвърлено.

объркващо? Нека да разгледаме как ще бъде написана нашата потребителска функция.

Както виждаме, приложихме методи then и catch към обекта promise (предишен пример).

След като изпълнителят завърши и разреши/отхвърлисъс стойност, въз основа на извиканото обратно извикване, или then, или catch ще бъдат изпълнени.

Ако можехме да проверим за място за паркиране, обещанието ще бъде решено с true/false. В този случай ще бъде изпълнена първата функция в метода then.

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

Можете също така напълно да пропуснете блока catch и да обработите и двата случая, като използвате самия метод then. Което би изглеждало така

Дали да използваме catch блок или да обработим грешката в then блок, зависи от нашите изисквания и дали обещанията са верижно свързани. Ще се потопим в Promise chaining в следващия раздел. Засега просто не забравяйте, че е възможно да се справите с грешката в самия блок then.

Сега нека завършим с практически пример

API за извличане ни позволява да правим мрежови заявки. Отговорът от fetch() ще бъде обещаниес стойност, която е отговорът, изпратен от сървъра.

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

Promise е мощен API и се надявам, че имате основни познания за него. Има много неща, които трябва да бъдат разгледани, като Promise chaining и различни методи като Promise.all(), Promise.any()което ще видим в предстоящите части.

Щракнете тук, за да преминете към следващата част, където разбирамеВеригите на обещанията.

Ако сте намерили тази статия за полезна, не забравяйте да ръкопляскате и да я споделите с приятелите си. Не забравяйте да ме следвате, тъй като обещавам да предоставям по-опростени обяснения ;)