habrahabr

Промисы в JavaScript простым языком

  • вторник, 17 декабря 2019 г. в 00:34:17
https://habr.com/ru/post/480522/
  • JavaScript
  • Программирование


Эта статья содержит простое объяснение, как работать с промисами, с краткими примерами кода. Если вы уже использовали промисы в JavaScript, вряд ли вы узнаете что-то новое — прим. перев.


JavaScript — это синхронный язык программирования, но благодаря колбэкам мы можем заставить его работать асинхронно. Вместе с колбэками приходит «Ад обратных вызовов». Промисы изобрели, чтобы писать асинхронные программы без него.


Промисы


Промисы (от английского Promise — обещание) очень похожи на обещания из реальной жизни.



  • После того, как обещание сделано, мы получаем обязательство выполнения «чего-то» в будущем и можем строить дальнейшие планы, исходя из этого
  • Как и в реальной жизни, обещания могут быть сдержаны или нарушены
  • Обещания не готовы мгновенно, мы можем работать с их результатами только после того, как обещания сдержаны

В JavaScript: «Объект Promise (промис) используется для отложенных и асинхронных вычислений».


Создание промисов


Создание объектов происходит по такому шаблону:


new Promise(function(resolve, reject) { ... });

Выполняющая функция (executor) принимает два аргумента resolve и reject, которые являются колбэками. Промисы используются для обработки асинхронных операций, являющихся блокирующим кодом. Обращения к БД, I/O или API — всё это примеры таких операций, с которыми должна разобраться выполняющая функция. Как только она завершится, она либо исполнит промис (вызовет resolve), либо отклонит его (вызовет reject).


Простой пример:


let promise = new Promise(function(resolve, reject) {

if(promise_kept) {
  resolve("done");
} else {
  reject(new Error("…"));  
}

});

Как видно, Promise не возвращает значение сразу. Он ждёт завершения блокирующей операции и вызывает подходящий колбэк. Это позволяет асинхронным методам возвращать значения, как если бы они были синхронными. Просто вместо возвращения значения (которого пока нет) возвращается промис.


Очевидно, что у промиса могут быть разные состояния:


  1. ожидание (pending): начальное состояние, не исполнен и не отклонен
  2. исполнено (fulfilled): операция завершена успешно
  3. отклонено (rejected): операция завершена с ошибкой

Пример:



Использование промисов


С созданием промисов проблем быть не должно, так что давайте перейдём к их использованию:


const isDone = new Promise()
//...

const checkIfDone = () => {
  isDone
    .then(ok => {
      console.log(ok)
    })
    .catch(err => {
      console.error(error)
    })
}

Вызов .checkIfDone() начнёт исполнение промиса isDone и дождётся его завершения, вызвав колбэк для результата. В случае ошибки будет вызван метод .catch().


Цепочка промисов


Методы промиса .then() и .catch() сами возвращают промис, для которого можно вновь вызвать .then() или .catch(), создав таким образом цепочку из промисов:


new Promise(function(resolve, reject) {

  setTimeout(() => resolve(1), 1000); 

}).then(function(result) { 

  alert(result); 
  return result * 3;

}).then(function(result) { 

  alert(result); 
  return result * 4;

}).then(function(result) {

  alert(result); 
  return result * 6;

});

В коде выше каждый промис передаёт результат своего исполнения в следующий .then() и так до полного завершения всей цепочки.


Заключение


Промисы, а точнее цепочки из них, позволяют нам контролировать порядок выполнения асинхронных операций в коде без ада обратных вывозов. В следующей статье мы разберём способ сделать асинхронный код ещё чище и понятнее.