promises
Промис
Промис хранит результат операции, который появится позже. У него три состояния: pending (ещё нет результата), fulfilled (есть значение) и rejected (есть ошибка).
resolve и reject — это функции, а не состояния. Срабатывает только первый вызов: повторный resolve или reject ничего не меняет.
const promise = new Promise((resolve, reject) => {
const ok = true;
if (ok) {
resolve('done');
} else {
reject(new Error('failed'));
}
});
promise.then(value => console.log(value)).catch(error => console.log(error));
then получает значение и возвращает новый промис. catch получает отказ. Цепочка и отличие catch от finally разобраны в заметке then-catch-finally.
Уже готовое значение
Promise.resolve сразу создаёт успешный промис, Promise.reject — отклонённый.
Promise.resolve(1).then(value => console.log(value)); // 1
Promise.reject(new Error('failed')).catch(error => console.log(error.message));
Таймер
Промис завершают внутри исполнителя, когда асинхронная операция закончилась.
const delay = ms => {
return new Promise(resolve => {
setTimeout(() => resolve('done'), ms);
});
};
delay(1000).then(value => console.log(value));
Событие
Тот же приём подходит для события. Наружу отдают функцию, которая возвращает промис.
const loadScript = src => {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = src;
script.onload = () => resolve(script);
script.onerror = () => reject(new Error(`Ошибка загрузки ${src}`));
document.head.append(script);
});
};
loadScript(
'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js',
)
.then(script => {
console.log(script.src);
return script;
})
.then(script => console.log('ещё один обработчик', script.src))
.catch(error => console.log(error.message));
Без return второй then получит undefined. Один промис можно подписать нескол ькими отдельными then: каждый получит одно и то же значение.
Несколько промисов
Promise.all ждёт все и сохраняет порядок результатов. Если один отклонится, весь результат отклонится.
Promise.all([loadPlanet(), loadPosts()]).then(([planet, posts]) => {
console.log(planet, posts);
});
Promise.allSettled дожидается всех, включая ошибки. У каждого пункта есть status: fulfilled или rejected.
Promise.allSettled([loadPlanet(), loadPosts()]).then(results => {
results.forEach(result => {
if (result.status === 'fulfilled') {
console.log(result.value);
} else {
console.log(result.reason);
}
});
});
Promise.race завершается первым успешным или первым отказом. Promise.any завершается первым успехом и отклоняется, только если отказали все.