Асинхронное программирование в JavaScript может быть выполнено с использованием следующих методов.

  1. Обратные вызовы
  2. Обещания
  3. Асинхронное ожидание
  4. Наблюдаемые

В этой статье мы сосредоточимся на обратных вызовах и промисах.

Говорят, что обещания лучше обратных вызовов.

Но многие люди, которые начинают использовать промисы, считают, что между промисами и обратными вызовами нет большой разницы. Это связано с тем, что они рассматривают промисы как обратные вызовы. Эта статья прольет свет на то, как правильно использовать Promise.

Для начала возьмем пример обратных вызовов. Добавьте два числа

function add(a,b,callback){
  setTimeout(function(){
   callback(a+b)
  },1)
}

Скажем, мы хотим добавить 4 числа, 1,2,3,4. Наша функция добавления принимает только 2 параметра за раз. Таким образом, нам придется сначала сложить два числа, а затем добавить результат к третьему и так далее.

add(1,2,function(result1){
   add(result1,3,function(result2){
      add(result2,4,function(result3){
         console.log(result3);
      });
   })
})

Этот код называется адом обратного вызова. По мере того, как он становится больше, становится очень трудно понимать и управлять этим кодом.

Давайте сделаем то же самое, используя промисы. Допустим, у нас есть еще одна функция addP, которая возвращает обещание, которое разрешается в результате сложения.

function addP(a,b){
  return new Promise(function(resolve,reject){
     setTimeout(function(){
        resolve(a+b);
     },1)
  });
}

Используя эту функцию addP, наш код для добавления 4 чисел будет выглядеть так:

addP(1,2).then(function(result1){      
   addP(result1,3).then(function(result2){
      addP(result2,4).then(function(result3){
         console.log(result3);
      });  
  });
})

Таким образом, даже после использования промисов структура кода остается прежней. Тогда какой смысл использовать обещание. Проблема здесь в том, что мы не используем функцию связывания промисов. Когда мы это сделаем, мы сможем избавиться от ада обратного вызова, как показано ниже.

addP(1,2).then(function(result1){      
   return addP(result1,3)
}).then(function(result2){
   return addP(result2,4)
}).then(function(result3){
   console.log(result3);
});

Понимание цепочки промисов

Цепочка работает, потому что then() возвращает другое обещание. Это обещание преобразуется в возвращаемое значение функции обработчика then. Давайте посмотрим на код, чтобы лучше понять.

let p = someAsyncCall();
let thenHandler = function(){
    return 10;
}
let p2 = p.then(thenHandler);
p2.then(function(result){
 console.log("p2 resolved value :",result); //10
})

В этом случае разрешенное значение p2 будет значением, возвращаемым thenHandler. В случае, если значение, возвращаемое thenHandler, является обещанием, p2 разрешится после того, как это обещание будет разрешено со значением этого обещания.

let p = someAsyncCall();
let thenHandler = function(){
    return Promise.resolve(20);//simple way to create a new promise //that will resolve to 20
}
let p2 = p.then(thenHandler);
p2.then(function(result){
 console.log("p2 resolved value :",result); //20
})

В следующей части мы увидим больше различий в обработке ошибок между промисами и обратными вызовами.