Въведение в промис в JavaScript

Вече знаете, че използването на callback-модела на асинхронност лесно води до ситуация на callback hell. Затова в JavaScript беше въведен нов модел, наречен промис (promise). Нека изучим този модел.

Промисът представлява обект, в който като параметър се предава функция, вътре в която трябва да поставяме нашия асинхронен код:

javascriptlet promise = new Promise(function() {
  // асинхронен код
});

Както виждате, записах обекта с промиса в променливата promise. На някое друго място в кода мога да приложа към тази променлива метода then, като предам в него функция с кода, който трябва да бъде изпълнен при завършване на асинхронния код, написан при създаването на този промис:

javascriptpromise.then(function() {
  // ще се изпълни при завършване на асинхронния код
});

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

javascriptsetTimeout(function() {
  let result = [1, 2, 3, 4, 5];
}, 3000);

Нека искам да реша за него нашия основен проблем на асинхронността: да изпълня някакъв код след задействане на таймера. При това не искам да поставям този код в самия таймер и искам в този код по някакъв начин да попадне резултатът, написан от мен в променливата result. В общи линии, ние решавахме този проблем в предишните уроци чрез callback-и и абонаменти. Нека сега видим как да го направим чрез промис.

Първо трябва да обвием нашия асинхронен код в промис:

javascriptlet promise = new Promise(function() {
  setTimeout(function() {
    let result = [1, 2, 3, 4, 5];
  }, 3000);
});

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

javascriptlet promise = new Promise(function(resolve) { // указваме параметър
  setTimeout(function() {
    let result = [1, 2, 3, 4, 5];
  }, 3000);
});

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

javascriptlet promise = new Promise(function(resolve) {
  setTimeout(function() {
    let result = [1, 2, 3, 4, 5];
    resolve(); // завършваме промиса
  }, 3000);
});

При това, ако искаме да предадем навън някакъв резултат от асинхронния код, можем да го предадем като параметър на нашата функция за завършване:

javascriptlet promise = new Promise(function(resolve) {
  setTimeout(function() {
    let result = [1, 2, 3, 4, 5];
    resolve(result); // предаваме резултата
  }, 3000);
});

Може, разбира се, да се отървем от междинната променлива:

javascriptlet promise = new Promise(function(resolve) {
  setTimeout(function() {
    resolve([1, 2, 3, 4, 5]);
  }, 3000);
});

Сега на всяко друго място можем да извикаме метода then на нашия промис:

javascriptpromise.then(function() {
  // ще се задейства при завършване на промиса
});

Резултатът от работата на промиса ще попадне в първия параметър на функцията, ако пожелаем да го укажем:

javascriptpromise.then(function(result) {
  console.log(result); // ще изведе масив с резултата
});
Задание 1

Направете промис, вътре в който има забавяне от 5 секунди, след което промисът трябва да се изпълни, като върне като резултат някакъв текст. Изведете този текст на екрана.