Получение результата в Promise
Допустим, папа обещает дать 100$, если вы сдадите завтрашний экзамен на хорошо или отлично.
В данный момент вы находитесь в состоянии ожидания, т.к. не знаете какую отметку вы получите, а следовательно, не знаете получите ли вы бонус в размере 100$.
Но как только вы получите отметку по экзамену, обещание завершится. Далее в зависимости от того успешно оно завершилось или нет будет зависеть получите ли вы 100$ или нет.
На JavaScript этот пример с помощью promise
реализуется следующим образом:
// создадим новый промис
const promise = new Promise((resolve, reject) => {
// оценку, которые мы получим определим случайным образом спустя некоторое время (например, 5 секунд)
setTimeout(() => {
// сгенерируем оценку от 2 до 5
const mark = Math.floor(Math.random() * 4) + 2;
// если оценка больше 3, то...
if (mark > 3) {
// завершим промис успешно: для этого вызовем функцию resolve() и передадим ей в скобках полученную оценку (это нужно для того, чтобы мы затем её могли получить в методе then())
resolve(mark);
} else {
// завершим промис с ошибкой
reject(mark);
}
}, 5000);
});
promise
// then выполнится в случае успеха
.then(result => console.log(`Ура! Я сдал экзамен на ${result}! Папа, как и обещал дал мне 100$.`))
// catch выполнится в случае ошибки
.catch(result => console.log(`Увы, я получил оценку ${result}! Папа мне не дал 100$`));
Создание промиса
Начинается процесс написания промиса с его создания. Осуществляется это с помощью конструктора, new Promise()
:
const promise = new Promise((resolve, reject) => {
// асинхронный код
});
Конструктор промиса принимает 2 аргумента, которые являются функциями. Первый аргумент обычно называют resolve
, а второй – reject
. Внутрь промиса помещают асинхронный код, можно конечно и синхронный, но тогда в этом не будет смысла.
Промис завершает своё выполнение, когда вызывается функция resolve()
или reject()
.
Функцию resolve()
вызывают обычно в том месте кода, в котором асинхронная операция должна завершиться успешно. А функцию reject()
– там, где она должна завершиться с ошибкой.
Состояния, в которых может находиться промис
Промис начинается с состояния ожидания state: "pending"
. Оно говорит о том, что он ещё не выполнен, результат undefined
.
Промис завершается после вызова resolve()
или reject()
. При этом его состояние переходит соответственно в выполнено state: "fulfilled"
или отклонено state: "rejected"
.
Внутрь функций resolve()
или reject()
можно поместить аргумент, который затем будет доступен соответственно в then()
или catch()
:
const passexam = true;
// промис
const result = new Promise((resolve, reject) => {
setTimeout(() => {
passexam ? resolve('Папа подарил 100$.') : reject('Папа не подарил 100$.');
}, 5000);
});
result
.then(value => {
console.log(result);
console.log(value);
})
.catch(value => {
console.log(result);
console.error(value);
});
Методы промисов
У каждого промиса есть определённый набор методов, которые мы можем использовать:
then
выполняется, когда промис завершился успешно (после вызова функцииresolve()
)catch
вызывается, если промис завершается ошибкой (после вызоваreject()
)finally
выполняется в любом случае после завершения промиса, вне зависимости от конечного состояния
Пример с использованием всех трёх методов:
<div><button id="run">Новая попытка</button></div>
<div id="result"></div>
<script>
let isProcess = false;
elResult = document.querySelector('#result');
document.querySelector('#run').onclick = () => {
if (isProcess) {
elResult.textContent = 'Подождите! Задача ещё выполняется!';
return;
}
isProcess = true;
elResult.textContent = 'Задача в процессе...';
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const mark = Math.floor(Math.random() * 4) + 2;
mark > 3 ? resolve(mark) : reject(mark);
}, 5000);
});
promise
.then(value => {
elResult.textContent = `Ура! Вы сдали экзамен на ${value}! Папа, как и обещал дал вам 100$.`;
})
.catch(value => {
elResult.textContent = `Увы, вы получили оценку ${value}! Папа не дал вам 100$`;
})
.finally(() => {
isProcess = false;
});
}
</script>
При этом then()
позволяет обработать не только успех, но и ошибку. Для этого необходимо передать функцию в качестве второго аргумента:
promise.then(
// действия при успешном завершении промиса
value => { },
// действия при завершении промиса с ошибкой
error => { }
);
Второй аргумент указывать не обязательно, в этом случае он будет реагировать только на успех:
promise.then(value => {
// действия при успешном завершении промиса
});
Для того чтобы получить значение из промиса в методах then()
и catch()
как уже было отмечено выше необходимо его передать в функции resolve()
и reject()
.