Promise – это специальный объект, который содержит своё состояние. Вначале pending («ожидание»), затем – одно из: fulfilled («выполнено успешно») или rejected («выполнено с ошибкой»). Используется для организации асинхронного кода - т.е. не сидим и не ждём завершения рдействия а выподняем что-то ещё.
var promise = new Promise(function(resolve, reject) {
// Эта функция будет вызвана автоматически
// В ней можно делать любые асинхронные операции,
// А когда они завершатся — нужно вызвать одно из:
// resolve(результат) при успешном выполнении
// reject(ошибка) при ошибке
})
resolve - выполняется в случае успеха, reject - в случае неудачи.
После создания promise для его использования - нужно навесить обработчики. Навешивание обработчиков происходит через ключевое слово then.
promise.then(onFulfilled, onRejected)
// Только обработчик успеха
promise.then(function(details) {
// handle success
});
// Только обработчик отказа
promise.then(null, function(error) {
// handle failure
});
// Обработчики успеха и отказа
promise.then(
function(details) { /* handle success */ },
function(error) { /* handle failure */ }
);
Для того, чтобы поставить обработчик только на ошибку, вместо .then(null, onRejected) можно написать .catch(onRejected) – это то же самое.
promise.catch(function(){})
Промисификация
Промисификация – это когда берут асинхронный функционал и делают для него обёртку, возвращающую промис. После промисификации использование функционала зачастую становится гораздо удобнее.
function httpGet() {
return new Promise(function(resolve, reject) {
setTimeout(() => {
let data = {id:1, name: 'John'};
resolve(data);
}, 300);
});
}
httpGet().then( data => console.log(data) ); // Object { id: 1, name: "John" }
Цепочки промисов
Каждый раз когда используется then - создаётся новое обещание и передаётся дальше по цепочке. Поэтому промисы удобно организовывать в цепочки. Для всей цепочки можно указать один обработчик .catch(onRejected).
let promise = new Promise(function(resolve, reject) {
setTimeout(() => {
Math.random() > .5 ? resolve({id: 1, name: 'John'}) : reject('Error');
}, 300);
});
promise
.then(function(data){
console.log('step 1');
})
.then(function(data){
console.log('step 2');
})
.catch(data => console.error(data))
.then(function(data){
console.info('promise finish');
})
;
// step 1
// step 2
// promise finish
Для того чтобы асинхронная цепочка могла быть продолжена в каждом then - нужно создать и вернуть промис.
let promise = new Promise(function(resolve, reject) {
console.log('promise start');
setTimeout(() => {
resolve({id: 1, name: 'John'});
}, 300);
});
promise
.then(data => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('step 1');
data.email = 'john@gmail.com';
resolve(data);
}, 300);
});
})
.then(data => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('step 2');
data.phone = '8-55-33-77';
resolve(data);
}, 300);
});
})
.then(function(data){
console.info('promise finish');
console.info(data);
});
// promise start
// step 1
// step 2
// promise finish
// Object { id: 1, name: "John", email: "john@gmail.com", phone: "8-55-33-77" }
Методы Promise.resolve(value) и Promise.reject(error) - позволяют моментально выполнить и отклонить обещания.
Параллельное выполнение
Вызов Promise.all(iterable) получает массив (или другой итерируемый объект) промисов и возвращает промис, который ждёт, пока все переданные промисы завершатся, и переходит в состояние «выполнено» с массивом их результатов.
function go(num){
return new Promise(function(resolve, reject){
let delay = Math.ceil(Math.random() * 3000);
console.log('nom =', num, 'delay =',delay);
// setTimeout( () => resolve(num), delay );
setTimeout( () => {
if(delay > 2000){
reject(num);
}
else{
resolve(num);
}
}, delay );
});
}
let p1 = go(1);
let p2 = go(2);
let p3 = go(3);
Promise.all([p3, p2, p1])
.then(value => console.log('value=', value))
.catch(error => console.warn(error))
;
// nom = 1 delay = 703
// nom = 2 delay = 705
// nom = 3 delay = 582
// value= Array [ 3, 2, 1 ]
Promise.race - получает итерируемый объект с промисами, которые нужно выполнить, и возвращает новый промис. Hезультатом будет только первый успешно выполнившийся промис из списка. Остальные игнорируются.
function go(num){
return new Promise(function(resolve, reject){
let delay = Math.ceil(Math.random() * 3000);
console.log('nom =', num, 'delay =',delay);
setTimeout( () => resolve(num), delay );
});
}
let p1 = go(1);
let p2 = go(2);
let p3 = go(3);
Promise.race([p3, p2, p1])
.then(value => console.log('value =', value))
.catch(error => console.warn(error))
;
// nom = 1 delay = 534
// nom = 2 delay = 1145
// nom = 3 delay = 427
// value = 3
Подробнее: