Делаем промис - шаг 4
Продолжаем писать собственную реализацию промиса.
На этом шаге мы завершим работу над методом then, а именно напишем обработчик для колбэка onRejected и добавим метод catch.
Напишем обработчик handleReject
then(onFulfilled, onRejected) {
/* .... другой код*/
const handleReject = () => {
if (typeof onRejected !== "function") {
reject(this.reason);
return;
}
try {
const result = onRejected(this.reason);
if (result instanceof MyPromise) {
result.then(resolve, reject);
return;
}
// важно, именно resolve
resolve(result);
} catch (e) {
reject(e);
}
}
}
Здесь есть ключевой момент: в конце вызывается resolve(result), а не reject(result).
Почему так?
По спецификации Promise/A+, если обработчик onRejected успешно обработал ошибку (то есть не выбросил исключение),
то цепочка промисов должна перейти в состояние fulfilled.
Другими словами onRejected - это аналог блока catch в try/catch: ошибка обработана, выполнение продолжается нормально.
Пример поведения настоящих промисов:
Promise.reject("error")
.then(null, (err) => {
console.log("handled: ", err);
return "ok"
})
.then(console.log);
// Вывод:
// handled error
// ok - цепочка стала успешной
Когда должен быть reject?
- Если сам обработчик
onRejectedвыбросил исключение
catch(() => throw new Error("new fail"))
- Если
onRejectedвернул промис, который перешел в состояние rejected.
метод catch
Метод catch в промисах - это просто сокращённая форма then:
promise.then(undefined, onRejected);
Поэтому его реализация выглядит так:
catch(onRejected) {
return this.then(undefined, onRejected);
}
Если успех обрабатывать не нужно, передаём undefined, а ошибку — в onRejected.
Теперь наш промис умеет корректно работать
как с успешными результатами, так и с ошибками — почти как нативный.
В следующем шаге напишем метод finally.