Основы JavaScript Promise API | Кодементор
Объект обещания представляет собой задачу, которая в конечном итоге будет завершена. Он предлагает множество замечательных функций и API, которые позволяют легко справляться с задачами, выполнение которых займет неопределенное время. Такие вещи, как сетевые вызовы, запросы к базе данных или любые другие действия, которые могут быть интенсивными, например, рендеринг большого количества элементов, должны использовать обещание.
Почему обещания?
При работе с ситуацией, когда трудно определить, когда задача будет завершена, потому что это зависит от внешней службы, которую мы не контролируем. Объекты промисов — это средство для асинхронного решения этих проблем с помощью эффективного API. Раньше в JavaScript мы использовали обратные вызовы для обработки асинхронных задач, однако у обратных вызовов было много проблем, когда дело доходило до обработки асинхронных задач, которые зависят друг от друга, и, следовательно, родились промисы.
Давайте сделаем new Promise
const someTask = new Promise((resolve, reject) => {})
Самый простой способ создать промис — это вызвать new Promise
конструктор. Давайте посмотрим на пример
3 состояния обещания
- Ожидание — когда вы только что создали обещание, оно будет отложено.
- Выполнено / Решено — Когда обещание выполнено
- Отклонено — когда произошла ошибка и обещанное значение не может быть определено
Итак, мы создаем экземпляр new Promise
и передать функцию с 2 аргументами resolve
а также reject
.Что resolve
а также reject
можно спросить. По сути resolve
следует вызывать, когда задача была успешно выполнена и reject
следует вызывать, если задача не удалась. Давайте продолжим наш пример. Мы будем использовать setTimeout для имитации асинхронной задачи, выполнение которой займет некоторое время. Эта задача в основном займет около 500 мс.
const calculation = new Promise((resolve, reject) => {
setTimeout(() => resolve(1 + 1), 500)
})
По сути, внутри обещания вы вызываете разрешение, когда задача завершена. Это в основном то, как обещание узнает, что задача была «решена».
После того, как вы определили промис, вам нужно получить результат этой функции. Следующий код запишет результат в консоль. В этом случае мы добавляем 1 + 1, поэтому мы вернем 2 на консоль.
calculation.then(result => console.log(result))
=> 2
Отклонение результата (обработка ошибок)
Скажем, например, у нас есть следующее, мы пытаемся выяснить, может ли кто-то пить кофе или нет.
const age = 7
const user = {name: 'zack'}
const checkCoffeeAble = new Promise((resolve, reject) => {
if (age >= 18) {
resolve(user)
} else {
reject("cannot have coffee")
}
})
const canHaveCoffee = (result) => {
localStorage('coffee_drinker', result.name)
}
const cannotHaveCoffee = (result) => {
console.log(result)
}
checkCoffeeAble.then(canHaveCoffee, cannotHaveCoffee)
В этом случае мы жестко задаем возраст, поэтому, вероятно, получим отклоненный результат на консоль. Но дело в том, что вы можете видеть, что мы по-прежнему обрабатываем отказы, используя then, мы просто передаем отклоненную функцию в качестве второго аргумента then. Мы также можем использовать такой захват.
checkCoffeeAble.then(canHaveCoffee).catch(cannotHaveCoffee)
Далее мы рассмотрим пример из реальной жизни, в котором мы фактически сделаем сетевой вызов, чтобы определить какой-то результат с помощью базовой логики.
Более надуманный пример
Допустим, мы хотим иметь возможность запрашивать github для популярного репо по имени темы, которое мы передаем в имени темы, и результат будет отображаться в dom. Таким образом, основной поток будет примерно таким.
- Позвоните в Github, используя fetch
- Получите данные из github и повторите их, используя карту внутри обещания.
- Отобразите результаты на странице.
- Если нет результатов, мы выводим сообщение об ошибке.
Причина, по которой мы делаем это таким образом,
- Мы не хотим просто использовать fetch, так как fetch уже возвращает Promise по умолчанию.
- Нам нужна какая-то рабочая нагрузка, которую можно решить с помощью нового промиса.
- Давайте setTimeout и console.log могут сделать довольно скучный пример.
Мы будем использовать обещание для обработки результатов и создания HTML-кода, который затем будем использовать для обновления dom. Здесь Код JS и codeandbox.
import "./styles.css";
const headers = {
Accept: "application/vnd.github.mercy-preview+json"
};
const getResults = topic =>
fetch(` {
headers
})
.then(response => response.json())
.then(body => body.items);
const renderItems = items =>
new Promise((resolve, reject) => {
if (Array.isArray(items) && items.length > 0) {
const data = items.map(item => `<h2>${item.name}</h2>`).join("");
resolve(data);
} else {
reject("<div>no results found try a different topic</div>");
}
});
const searchTopics = topic => {
document.getElementById("app").innerHTML = "<h1>Loading...</h1>";
getResults(topic)
.then(renderItems)
.then(html => {
document.getElementById("app").innerHTML = `
<div class="results">
<h1>results for: ${topic}</h1>
${html}
</div>
`;
})
.catch(error => {
document.getElementById("app").innerHTML = `
<div class="error">${error}</div>
`;
});
};
// try passing in "89348598095380953" for error response
searchTopics("machine learning");
Основная функция, использующая пользовательский промис, находится здесь.
const renderItems = items =>
new Promise((resolve, reject) => {
if (items.length > 0) {
const data = items.map(item => `<h2>${item.name}</h2>`).join("");
resolve(data);
} else {
reject("<div>no results found try a different topic</div>");
}
});
Давайте немного разберем это в операторе if, мы проверяем, действительно ли сетевой вызов вернул результат. Если ничего не было возвращено, мы используем reject, если что-то было возвращено, мы повторяем и используем разрешение, когда итерация завершена.
Вот как это называется.
getResults(topic)
.then(renderItems)
.then(html => {
document.getElementById("app").innerHTML = `
<div class="results">${html}</div>
`;
})
.catch(error => {
document.getElementById("app").innerHTML = `
<div class="error">${error}</div>
`;
});
Сначала мы используем getResults(topic), затем мы передаем наше обещание renderItems как функцию обратного вызова, затем мы обрабатываем сценарий успеха, отображая результаты в div результатов, и если у нас нет возвращенных результатов, мы перехватываем и отображаем сообщение об ошибке. разд.
Заворачивать
Поначалу промисы могут показаться немного пугающими, но в целом они открывают лучший способ писать асинхронный код, не страдая от ада обратных вызовов. Этот пост задуман как введение в промисы, в следующем посте мы покажем вам альтернативный синтаксис (async/await) для промисов, который еще больше упрощает написание асинхронного кода в JavaScript, и мы посмотрим, как мы можем очистить наш пример использования async/await.
Если у вас есть какие-либо вопросы / опасения по поводу этого поста, не стесняйтесь задать вопрос или оставить отзыв здесь.