Традиционный способ обработки асинхронных вызовов в JavaScript - обратные вызовы.
Скажем, нам нужно было сделать три звонка на сервер, один за другим, чтобы настроить наш
приложение. С обратными вызовами код может выглядеть примерно так:
функция xhrGET для вызова сервера):
// Fetch some server configuration
xhrGET('/api/server-config', function(config) {
// Fetch the user information, if he's logged in
xhrGET('/api/' + config.USER_END_POINT, function(user) {
// Fetch the items for the user
xhrGET('/api/' + user.id + '/items', function(items) {
// Actually display the items here
});
});
});
В этом примере мы сначала выбираем конфигурацию сервера. Затем на основе этого мы получаем
информация о текущем пользователе, а затем, наконец, получить список элементов для текущего
пользователь. Каждый вызов xhrGET принимает функцию обратного вызова, которая выполняется, когда сервер
отвечает.
Теперь, конечно, чем больше у нас уровней вложенности, тем сложнее код читать, отлаживать,
поддерживать, обновлять и в основном работать с. Это вообще известно как ад обратного вызова.
Кроме того, если нам нужно обработать ошибки, нам, возможно, нужно передать другую функцию каждому
Вызов xhrGET, чтобы сообщить, что нужно делать в случае ошибки. Если бы мы хотели иметь только один
общий обработчик ошибок, это невозможно.
API Promise был разработан для решения этой проблемы со
проблема обработки ошибок.
API Promise предлагает следующее:
- Каждая асинхронная задача возвращает объект
promise
.
- Каждый объект
promise
будет иметь функцию then
, которая может принимать два аргумента, success
обработчик и обработчик error
.
- Успешный или обработчик ошибок в функции
then
будет вызываться только один раз , после
асинхронная задача завершается.
- Функция
then
также возвращает promise
, чтобы разрешить цепочку из нескольких вызовов.
- Каждый обработчик (успех или ошибка) может вернуть
value
, который будет передан следующему
функционировать как argument
, в цепочке promise
с.
- Если обработчик возвращает
promise
(делает другой асинхронный запрос), то следующий
Обработчик (успех или ошибка) будет вызван только после того, как этот запрос будет завершен.
Так что предыдущий пример кода может перевести что-то вроде следующего, используя
обещания и сервис $http
(в AngularJs):
$http.get('/api/server-config').then(
function(configResponse) {
return $http.get('/api/' + configResponse.data.USER_END_POINT);
}
).then(
function(userResponse) {
return $http.get('/api/' + userResponse.data.id + '/items');
}
).then(
function(itemResponse) {
// Display items here
},
function(error) {
// Common error handling
}
);
Распространение успеха и ошибки
Цепные обещания - очень мощная техника, которая позволяет нам выполнять много
функциональность, например, когда служба выполняет серверный вызов, выполняет некоторую постобработку
данные, а затем вернуть обработанные данные в контроллер. Но когда мы работаем с
promise
цепи, есть несколько вещей, которые мы должны иметь в виду.
Рассмотрим следующую гипотетическую promise
цепочку с тремя обещаниями, P1, P2 и P3.
Каждый promise
имеет обработчик успеха и обработчик ошибок, поэтому S1 и E1 для P1, S2 и
E2 для P2 и S3 и E3 для P3:
xhrCall()
.then(S1, E1) //P1
.then(S2, E2) //P2
.then(S3, E3) //P3
В нормальном потоке вещей, где нет ошибок, приложение будет работать
через S1, S2 и, наконец, S3. Но в реальной жизни все не так гладко. P1 может
обнаружите ошибку, или P2 может столкнуться с ошибкой, вызвав E1 или E2.
Рассмотрим следующие случаи:
• Мы получили успешный ответ от сервера в P1, но возвращенные данные не
правильно, или на сервере нет данных (например, пустой массив). В таком
В этом случае для следующего обещания P2 он должен вызвать обработчик ошибок E2.
• Мы получаем ошибку для обещания P2, запускающую E2. Но внутри обработчика мы имеем
данные из кэша, гарантируя, что приложение может загружаться как обычно. В таком случае,
мы можем убедиться, что после E2 вызывается S3.
Таким образом, каждый раз, когда мы пишем успех или обработчик ошибок, нам нужно сделать вызов - учитывая
текущая функция, является ли это обещание успешным или неудачным для следующего обработчика в обещании
цепь
Если мы хотим запустить обработчик успеха для следующего обещания в цепочке, мы можем просто
вернуть значение из успеха или обработчик ошибок
Если, с другой стороны, мы хотим вызвать обработчик ошибок для следующего обещания в
цепочка, мы можем сделать это, используя объект deferred
и вызывая его метод reject()
Теперь, что такое отложенный объект?
Отложенные объекты в jQuery представляют собой единицу работы, которая будет
завершается позже, как правило, асинхронно. После единицы работы
завершено, для объекта deferred
может быть установлено разрешение или ошибка.
A deferred
объект содержит promise
объект. Через объект promise
Вы можете указать, что должно произойти после завершения единицы работы. Вы
сделать это, установив функции обратного вызова для объекта promise
.
Отложенные объекты в Jquery: https://api.jquery.com/jquery.deferred/
Отложенные объекты в AngularJs: https://docs.angularjs.org/api/ng/service/$q