Проблема с пониманием Promise (JavaScript)
Уже сижу целую неделю и никак не могу понять Promise. Все что знаю, это то, что это связанно с асинхронностью в JS (скорее ее имитацией). Мне еще дали задание по ним на курсах от одной компании, предварительно не разобрав тему...
//Представьте ситуацию: у вас есть необходимость составить объект с данными о пользователе,
// который в дальнейшем будете использовать в работе.
const promise1 = new Promise(resolve) => {
setTimeout(() => Promise.resolve('Cherkasy'), 1000); // локация
}
const promise2 = new Promise(resolve) => {
setTimeout(() => Promise.resolve('admin'), 4000); // ролей три - guest, user, admin
}
const promise3 = new Promise(resolve) => {
setTimeout(() => Promise.resolve('1'), 2000); // id пользователя, можете юзать любое число
}
const promise4 = new Promise(resolve) => {
setTimeout(() => Promise.resolve(['Саша', 'Влад', 'Юля', 'Андрей', 'Богдан']), 1000); // массив который показывает людей, состоящих в группе у человека
}
//Необходимо построить цепочку промисов.
- Первый промис - отдает локацию пользователя (город).
- Второй - его роль и в зависимости от роли вам необходимо составить ему email(если пользователь admin - email должен заканчиваться на admin.com и аналогично с другими ролями).
- Далее если пользователь admin вам необходимо вызвать функцию, передав в нее id пользователя и в зависимости от id вернуть число, которое будет обозначать к-во человек в его группе (для этой функции можно юзать промисификацию, соответствие id к к-ву человек придумайте сами, это может быть объект с ключом id и значением к-вом человек. {1: 3, 2: 5} и тд)
- Итого если пользователь на админ, а пришел цепочка должна проигнорировать список человек в группе, только выкинуть ошибку с помощью throw new Error(текст ошибки туть). Если пользователь админ но пришло к-во человек в группе больше, чем указано - выкинуть соответствующую ошибку, цепочка проминов должна завершиться с ошибкой которая дает понять что случилось.
- Для построения подобных сценариев вы можете изменять исходное состояние промисов, делая их rejected если необходимо. Так же данные что передаются тоже можно изменять, но не изменяем время в setTimeout.
Собственно вот задание. Я не понимаю как строить цепочку промисов, что должно за чем идти, где должны быть какие-то вложенности. Прошу кто может объяснить? Или может мне нужно предварительно что-то знать, чтоб понять это?
Ответы (1 шт):
Вы неправильно обрабатываете Promise-объект. Для начала вот вам мат. часть Promise on MDN
Promise - это встроенный класс, соответственно при создании нового объекта через оператор new, вы должны вызвать один из callback-методов в контексте того Promise объекта, который создали. Два разных выражения new Promise() и Promise.resolve() порождают абсолютно разные контексты, иными словами это два разных объекта со своими внутренними обработчиками resolve и reject. Данные обработчики инкапсулированы во внутренний механизм промиса. При вызове одного из этих обработчиков вы порождаете действие о завершении операции передав этим обработчикам данные в качестве аргументов resolve(data) или reject(new Error('some error')). Метод resolve для успешной операции, а reject для ошибок.
Соответственно создав новый объект Promise, вы неправильно его обработали, и данный промис, созданный через оператор new никогда не выполнится, потому что он не обрабатывается должным образом.
const promise1 = new Promise((resolve) => {
setTimeout(() => Promise.resolve('Cherkasy'), 1000);
});
Давайте проанализируем почему.
- Вы создаете переменную
promise1и сохраняете в ней инстанс на промис - В теле данного промиса вы вызываете
setTimeoutи после ожидания 1сек, вместо того чтобы вызватьresolveилиrejectсозданного выше промиса вы создаете новый промисPromise.resolve. - Так как
setTimeoutне способен возвращать результаты кастомных методов, а созданный промис через операторnewникогда не обрабатывается, в переменнойpromise1сохраняется состояние промиса, которое никогда не завершится.
Вот так необходимо обрабатывать Promise с помощью setTimeout
const resolvedPromise = new Promise((resolve) => {
setTimeout(() => resolve('Cherkasy'), 1000);
});
const rejectedPromise = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error('Cherkasy not found')), 1200);
});
Но иногда бывает что не нужно прибегать к setTimeout и созданию нового объекта Promise, потому как результат нам уже известен и не нужно ожидать. Но для того чтобы соблюсти контракт данных используя Promise, разработчики придумали вот такое выражение:
const resolvedPromise = Promise.resolve('Cherkasy');
const rejectedPromise = Promise.reject(new Error('Cherkasy not found'));
Весь вышеперечисленный код можно обрабатывать двумя способами и между этими способами существенная разница (Во первых это разное оформление, во вторых при использовании async/await, интерпретатор дойдя до оператора await, приостановит выполнение метода в контексте которого был вызван await, до тех пор пока Promise не вернет результат):
// Обработка Promise с помощью async/await
async function() {
try {
const data1 = await resolvedPromise;
} catch (error) {
console.error(error);
}
try {
const data2 = await rejectedPromise;
} catch (error) {
console.error(error);
}
}
// Обработка Promise с помощью then/catch
resolvedPromise
.then(data => console.log(data))
.catch(error => console.error(error))
.then(() => rejectedPromise)
.then(data => console.log(data))
.catch(error => console.error(error))
;